Skip to content

Commit bf9999d

Browse files
refactor(i18n): Cache localized resources to improve performance
This commit introduces a caching mechanism for localized `Resources` to prevent their repeated recreation, leading to performance improvements. The changes include: - A new `LocalizedResourcesProvider` object to cache `Resources` based on the current `Locale`. The cache is synchronized to ensure thread safety. - Refactoring `getLocalizedString` and `getLocalizedStringArray` to use the new provider, which simplifies the code and eliminates redundant `Context` creation. - Clearing the `LocalizedResourcesProvider` cache when the app language is changed in `SettingsFragment` to ensure the UI is re-rendered with the correct translations.
1 parent c114d81 commit bf9999d

File tree

3 files changed

+60
-22
lines changed

3 files changed

+60
-22
lines changed

app/src/main/java/com/github/droidworksstudio/common/ContextExtensions.kt

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import android.content.IntentFilter
1212
import android.content.pm.ApplicationInfo
1313
import android.content.pm.PackageManager
1414
import android.content.res.Configuration
15+
import android.content.res.Resources
1516
import android.net.Uri
1617
import android.os.BatteryManager
1718
import android.os.Bundle
@@ -308,37 +309,32 @@ fun Context.isBiometricEnabled(): Boolean {
308309
}
309310
}
310311

311-
fun getLocalizedString(@StringRes stringResId: Int, vararg args: Any): String {
312-
// Get the context from Mlauncher. It's guaranteed to never be null
312+
private fun currentAppResources(): Resources {
313313
val context = Mlauncher.getContext()
314+
val prefs = Prefs(context)
315+
val locale = Locale.forLanguageTag(prefs.appLanguage.locale().toString())
316+
return LocalizedResourcesProvider.getResources(context, locale)
317+
}
314318

315-
val localPrefs = Prefs(context)
316-
val locale = Locale.forLanguageTag(localPrefs.appLanguage.locale().toString())
317-
val config = Configuration(context.resources.configuration)
318-
config.setLocale(locale)
319-
val localizedContext = context.createConfigurationContext(config)
320-
321-
// Return the localized string with or without arguments
319+
fun getLocalizedString(
320+
@StringRes stringResId: Int,
321+
vararg args: Any
322+
): String {
323+
val res = currentAppResources()
322324
return if (args.isEmpty()) {
323-
localizedContext.getString(stringResId) // No arguments, use only the string resource
325+
res.getString(stringResId)
324326
} else {
325-
localizedContext.getString(stringResId, *args) // Pass arguments to getString()
327+
res.getString(stringResId, *args)
326328
}
327329
}
328330

329-
fun getLocalizedStringArray(@ArrayRes arrayResId: Int): Array<String> {
330-
// Get the context from Mlauncher. It's guaranteed to never be null
331-
val context = Mlauncher.getContext()
332-
333-
val localPrefs = Prefs(context)
334-
val locale = Locale.forLanguageTag(localPrefs.appLanguage.locale().toString())
335-
val config = Configuration(context.resources.configuration)
336-
config.setLocale(locale)
337-
val localizedContext = context.createConfigurationContext(config)
338-
// Return the localized string array
339-
return localizedContext.resources.getStringArray(arrayResId)
331+
fun getLocalizedStringArray(
332+
@ArrayRes arrayResId: Int
333+
): Array<String> {
334+
return currentAppResources().getStringArray(arrayResId)
340335
}
341336

337+
342338
fun Context.openAccessibilitySettings() {
343339
val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
344340
val cs = ComponentName(this.packageName, ActionService::class.java.name).flattenToString()
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.github.droidworksstudio.common
2+
3+
import android.content.Context
4+
import android.content.res.Configuration
5+
import android.content.res.Resources
6+
import java.util.Locale
7+
8+
object LocalizedResourcesProvider {
9+
10+
@Volatile
11+
private var cachedLocale: Locale? = null
12+
13+
@Volatile
14+
private var cachedResources: Resources? = null
15+
16+
fun getResources(context: Context, locale: Locale): Resources {
17+
if (cachedLocale == locale && cachedResources != null) {
18+
return cachedResources!!
19+
}
20+
21+
synchronized(this) {
22+
if (cachedLocale != locale || cachedResources == null) {
23+
val config = Configuration(context.resources.configuration)
24+
config.setLocale(locale)
25+
26+
val localizedContext = context.createConfigurationContext(config)
27+
cachedResources = localizedContext.resources
28+
cachedLocale = locale
29+
}
30+
return cachedResources!!
31+
}
32+
}
33+
34+
fun clearCache() {
35+
synchronized(this) {
36+
cachedLocale = null
37+
cachedResources = null
38+
}
39+
}
40+
}

app/src/main/java/com/github/droidworksstudio/mlauncher/ui/SettingsFragment.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import androidx.core.os.bundleOf
5252
import androidx.lifecycle.ViewModelProvider
5353
import androidx.navigation.fragment.findNavController
5454
import com.github.droidworksstudio.common.AppLogger
55+
import com.github.droidworksstudio.common.LocalizedResourcesProvider
5556
import com.github.droidworksstudio.common.getLocalizedString
5657
import com.github.droidworksstudio.common.isBiometricEnabled
5758
import com.github.droidworksstudio.common.isGestureNavigationEnabled
@@ -587,6 +588,7 @@ class SettingsFragment : BaseFragment() {
587588
val newLanguage = languageEntries[newLanguageIndex]
588589
selectedLanguage = newLanguage // Update state
589590
prefs.appLanguage = newLanguage // Persist in preferences
591+
LocalizedResourcesProvider.clearCache()
590592
requireActivity().recreate() // force reload with new language
591593
}
592594
}

0 commit comments

Comments
 (0)