Обновление заданий стека после изменения ночного режима
Я видел много вопросов и ответов о воссоздании текущей активности после изменения ночного режима приложения, но я ничего не видел о том, как обновить действия Backstack.
Скажем, у меня есть backstack A > B > C. Активность C позволяет изменить ночной режим, вызвав AppCompatDelegate.setDefaultNightMode()
, После этого вызова текущая активность (C) может обновить свою тему delegate.applyDayNight()
или же recreate()
,
Однако, когда пользователь возвращается к B или A, действия все еще используют "старый" режим, днем или ночью.
Я пытался добавить что-то подобное в деятельность:
override fun onResume() {
super.onResume()
delegate.applyDayNight()
}
Но это не похоже на работу.
Я сделал несколько попыток исправить это:
Одной из идей было бы воссоздать backstack полностью, как предложено здесь или здесь, но, поскольку backstack не является статичным, это не выполнимо для меня.
Другой идеей было бы иметь класс, который обрабатывает смену ночного режима и предоставляет LiveData. Каждая активность будет слушать LiveData для изменения режима и вызова recreate()
, Однако мы застряли в бесконечном цикле, потому что Activity будет воссоздавать сразу после начала прослушивания LiveData.
Мне трудно поверить, что я первый, кто пытается обновить активность из бэкстека после смены ночного режима. Что я упустил?
Спасибо!
0 ответов
Если вы можете определить, когда изменился дневной / ночной режим, вы можете просто воссоздать занятие, которое возобновляется при извлечении заднего стека.
В следующей демонстрации есть три действия: A, B и C. A create B и B создает C. Деятельность C может изменить дневной / ночной режим. Когда C выталкивается, действие B видит изменения в дневном / ночном режиме и звонит reCreate()
воссоздать активность. То же самое происходит в действии A, когда действие B прерывается.
Видео ниже показывает эффект. Светлый фон - это "дневной" режим, а темный - "ночной".
Я создал проект GitHub для этого демонстрационного приложения. Если это работает как решение, я могу включить больше текста в ответ из проекта.
Полное обновление вашего заднего стека, вероятно, является излишним и может добавить некоторые издержки / задержки в UX; и, как вы упомянули, большинство приложений не будет иметь доступа к полному статическому бэк-стеку.
По сути, вы описываете более общую проблему: глобальные изменения темы или самого WindowManager влияют на последующее рисование представлений. Но предыдущие макеты для действий в стеке не могут быть перерисованы. Это может показаться странным для вас в этой ситуации, но также может быть много веских причин, по которым вы не захотите перерисовывать активность в стеке, если пользователь вернется к ней. И поэтому это не автоматическая функция.
Я могу придумать пару вариантов:
1) Напишите собственный класс, унаследованный от Activity, который делает недействительными все его представления, когда он снова перемещается в начало стека. Например в onResume()
или же onRestart()
позвоните (если в Fragment
)
View view = getActivity().findViewById(R.id.viewid);
view.invalidate();
Используйте эту пользовательскую активность для всех ваших действий, которые вы хотите сохранить в соответствии с текущим режимом дня / ночи.
2) Использование ActivityLifecycleCallbacks
, Это помогает хранить всю логику в одном месте и избавляет от необходимости настраиваемого наследования, как указано выше. Вы можете сделать недействительными свои взгляды, если действия будут приостановлены / возобновлены. Вы можете включить Listener, если ваше приложение меняет тему, и записать как SharedPreference
, например.
Чтобы использовать, добавьте обратные вызовы в ваш класс приложения:
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
@Override
public void
onActivityCreated(Activity activity, Bundle savedInstanceState) {
//can check type of Activity for custom behaviour, if using inheritance
if(activity instanceof MainActivity) {
mMainActivities.put(activity, new MainActivityEntry((MainActivity)activity));
//...
}
}
@Override
public void
onActivityDestroyed(Activity activity) {
}
@Override
public void
onActivityPaused(Activity activity) {
}
@Override
public void
onActivityResumed(Activity activity) {
if(activity instanceof MainActivity) {
//...
}
//can update Entry properties too
final MainActivityEntry activityEntry = mMainActivities.get(activity);
if(activityEntry != null) {
//record state /perform action
}
}
@Override
public void
onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void
onActivityStarted(Activity activity) {
}
@Override
public void
onActivityStopped(Activity activity) {
}
});
Быстрый ответ:
@Override
protected void onRestart() {
super.onRestart();
recreate();
}
Вы добавляете приведенные выше коды в свой MainActivity, и он будет работать.
Создайте статическую логическую переменную в проекте и в каждом действии проверяйте, является ли логическое значение истинным или ложным, затем применяйте дневной и ночной на основе значения.