Вопрос или проблема
Я хочу настроить изменение локали в зависимости от выбранных параметров. Как только пользователь выбирает язык, вызывается API AppCompatDelegate, чтобы уведомить Android об изменении языка. Предпочтения языков для приложений
Но приложение перезапускается. Как избежать перезапуска приложения при изменении локали?
В манифесте уже добавлена локаль в android:configChanges
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="locale|keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
Вот мой модуль:
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import android.os.Build
import com.facebook.react.bridge.*
class LocaleModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
override fun getName(): String {
return "LocaleModule"
}
@ReactMethod
fun setApplicationLocales(localesArray: ReadableArray, promise: Promise) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
try {
val locales = Array(localesArray.size()) { "" }
for (i in 0 until localesArray.size()) {
locales[i] = localesArray.getString(i) ?: ""
}
val localeList = LocaleListCompat.forLanguageTags(locales.joinToString(","))
AppCompatDelegate.setApplicationLocales(localeList)
promise.resolve(null)
} catch (e: Exception) {
promise.reject("ERROR", e.message ?: "Неизвестная ошибка")
}
} else {
promise.reject("UNSUPPORTED", "Уровень API ниже 33")
}
}
@ReactMethod
fun getApplicationLocales(promise: Promise) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
try {
val localeList = AppCompatDelegate.getApplicationLocales()
val localesArray = WritableNativeArray()
for (i in 0 until localeList.size()) {
localesArray.pushString(localeList[i]?.toLanguageTag())
}
promise.resolve(localesArray)
} catch (e: Exception) {
promise.reject("ERROR", e.message ?: "Неизвестная ошибка")
}
} else {
promise.reject("UNSUPPORTED", "Уровень API ниже 33")
}
}
}
Пакет:
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.uimanager.ViewManager
import com.facebook.react.bridge.ReactApplicationContext
class LocalePackage: ReactPackage {
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
override fun createNativeModules(
reactContext: ReactApplicationContext
): List<NativeModule> {
return listOf(LocaleModule(reactContext))
}
}
Ответ или решение
Чтобы избежать перезапуска вашего приложения при изменении локали, следует обратиться к особенностям обработки конфигурационных изменений в Android. Процесс автоматически вызывает перезапуск activity при изменении локали, если вы не обрабатываете это явно. Вы уже добавили android:configChanges
, что является первым шагом к решению проблемы, однако есть дополнительные моменты, которые необходимо учитывать.
1. Поддержка configChanges
Вы правильно указываете местоположение конфигурационных изменений в вашем манифесте. Вам нужно убедиться, что вы добавили нужные параметры в android:configChanges
, особенно для локали:
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="locale|layoutDirection|screenLayout|screenSize|smallestScreenSize|uiMode|orientation|keyboard|keyboardHidden"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"
android:exported="true">
</activity>
Ключевое слово locale
должно быть включено, чтобы перехватывать изменения в локали.
2. Переопределение метода onConfigurationChanged
Помимо указания конфигурационных изменений в манифесте, вам нужно переопределить метод onConfigurationChanged
в вашем MainActivity
, чтобы обработать изменение локали. Например:
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Можно обновить UI или выполнить дополнительные действия после изменения локали
}
3. Корректное использование AppCompatDelegate
При использовании AppCompatDelegate
для изменения языковых настроек, убедитесь, что вызовы производятся в правильном контексте и вы обновляете нужные компоненты UI после изменения локали. Ваш метод setApplicationLocales
выглядит корректно для установки новых локалей.
Тем не менее, если вы также хотите обновлять UI без перезапуска, вам может понадобиться вручную обновить тексты в вашем приложении. Например, вы можете вызвать пересоздание активити (если это необходимо):
recreate()
4. Обновление локали в приложении
После изменения локали также стоит пересоздать компоненты интерфейса (если они зависят от локализации). Пример:
private fun updateLocale(locale: Locale) {
val config = resources.configuration
config.setLocale(locale)
resources.updateConfiguration(config, resources.displayMetrics)
recreate() // Пересоздание активити, если это необходимо
}
Заключение
Соблюдая вышеперечисленные рекомендации, вы сможете избежать ненужных перезапусков вашего приложения при изменении локали. Убедитесь, что вы обрабатываете изменения в методе onConfigurationChanged
, и правильно применяете AppCompatDelegate
.
Не забудьте протестировать изменения на различных устройствах и версиях Android для проверки их работоспособности.