RN Android перезапускает активити при изменении локали

Вопрос или проблема

Я хочу настроить изменение локали в зависимости от выбранных параметров. Как только пользователь выбирает язык, вызывается 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 для проверки их работоспособности.

Оцените материал
Добавить комментарий

Капча загружается...