Как пересоздать активити с данными при смене тёмной темы?
По нажатию на кнопку во view model у меня меняется тема:
R.id.appBarActionTheme -> {
val nightMode = preferenceRepository.nightMode
preferenceRepository.nightMode = appContext.switchDarkLightMode(nightMode)
}
Вот сам метод:
fun Context.switchDarkLightMode(currentMode: Int): Int {
val newMode = when (currentMode) {
AppCompatDelegate.MODE_NIGHT_YES -> AppCompatDelegate.MODE_NIGHT_NO
AppCompatDelegate.MODE_NIGHT_NO -> AppCompatDelegate.MODE_NIGHT_YES
else -> {
if (this.isDarkThemeSet()) AppCompatDelegate.MODE_NIGHT_NO
else AppCompatDelegate.MODE_NIGHT_YES
}
}
AppCompatDelegate.setDefaultNightMode(newMode)
return newMode
}
И загвоздка в том, что при вызове данного метода setDefaultNightMode, пересоздаётся активити, примерно как при повороте экрана.
И у меня перезапускается приложение, которое в свою очередь сразу отобрает блокировку.
Чтобы снять блокировку я передавал в Intent данные которые после обрабатывал и мог пропустить экран блокировки, делал я примерно следующим образом
fun restartLockableActivity() {
startActivity(Intent(this, this.javaClass).apply { putExtra(KEY_SKIP_PIN, true) })
finish()
}
Но как сейчас обойти этот момент я не знаю и не уверен что сэтить Intent хороший вариант, к тому же он у меня не срабатывает
Если я добавлю что то подобное в функцию расшерения switchDarkLightMode следующие строки:
val intent = Intent(this, this.javaClass).apply { putExtra(KEY_SKIP_PIN, true) }
(this as? Activity)?.intent = intent
ВОПРОС: Как переключать тему без перегрузки activity или перегружать так чтобы можно было засунуть данные Intent'а?
Ответы (1 шт):
Честно говоря, без полной картины архитектуры приложения сложно дать однозначный ответ. Для сохранения данных есть довольно много способов. Если вы используете MVVM в сочетании с LiveData могу дать своё решение. Что насчет интентов для передачи информации, то это далеко не лучший вариант конечно же. Для упрощения навигации могу порекомендовать взглянуть на Navigation Component, там довольно простая реализация.
Либо еще как вариант, для восстановления состояния активности/фрагмента по классике можно использовать onSaveInstanceState(outState: Bundle) или setRetainInstance(true);
Возможно моё решение поможет, либо хотя бы натолкнёт на правильные мысли.
MainActivity.kt
class MainActivity : AppCompatActivity(){
private lateinit var viewModel: ExampleViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//инициализируем слушатель для кнопки смены темы
switch_theme_mode.setOnClickListener {
viewModel.switchTheme()
}
initViewModel()
}
}
private fun initViewModel(){
viewModel = ViewModelProviders.of(this).get(ExampleViewModel::class.java)
)
viewModel.getTheme().observe(this, Observer { updateTheme(it) })
}
private fun updateTheme(mode: Int) {
delegate.setLocalNightMode(mode)
}
ExampleViewModel.kt
class ExampleViewModel : ViewModel() {
private val repository: PreferencesRepository = PreferencesRepository
private val appTheme = MutableLiveData<Int>()
init {
appTheme.value = repository.getAppTheme()
}
fun getTheme(): LiveData<Int> = appTheme
fun switchTheme() {
if (appTheme.value == AppCompatDelegate.MODE_NIGHT_YES) {
appTheme.value = AppCompatDelegate.MODE_NIGHT_NO
} else {
appTheme.value = AppCompatDelegate.MODE_NIGHT_YES
}
repository.saveAppTheme(appTheme.value!!)
}
}
PreferencesRepository.kt
object PreferencesRepository {
private const val APP_THEME = "APP_THEME"
private val prefs: SharedPreferences by lazy {
val ctx = App.applicationContext()
PreferenceManager.getDefaultSharedPreferences(ctx)
}
fun saveAppTheme(theme: Int) {
putValue(APP_THEME to theme)
}
fun getAppTheme() : Int = prefs.getInt(APP_THEME,
AppCompatDelegate.MODE_NIGHT_NO)
App.kt (не забудьте указать имя и тему в манифесте)
class App : Application() {
companion object{
private var instance:App? = null
fun applicationContext(): Context {
return instance!!.applicationContext
}
}
init {
instance = this
}
override fun onCreate() {
super.onCreate()
PreferencesRepository.getAppTheme().also {
AppCompatDelegate.setDefaultNightMode(it)
}
}
}