He visto muchas preguntas y respuestas sobre cómo recrear la actividad actual después de cambiar el modo nocturno de la aplicación, pero no he visto nada sobre cómo actualizar las actividades de la pila de respaldo.
Digamos que tengo la pila trasera A > B > C . La actividad C permite cambiar el modo nocturno llamando a AppCompatDelegate.setDefaultNightMode()
. Después de esta llamada, la actividad actual (C) puede actualizar su tema con delegate.applyDayNight()
o recreate()
.
Sin embargo, cuando el usuario navega de regreso a B o A, las actividades todavía usan el modo "antiguo", ya sea de día o de noche.
Intenté agregar algo así a las Actividades:
override fun onResume() { super.onResume() delegate.applyDayNight() }
pero no parece funcionar.
Hice varios intentos de arreglar esto:
Una idea sería recrear la pila trasera completamente como se sugiere aquí o aquí , pero como la pila trasera no es estática, no es factible para mí.
Otra idea sería tener una clase que maneje el cambio de modo nocturno y proporcione un LiveData. Cada actividad escucharía LiveData para un cambio de modo y llamaría a recreate()
. Sin embargo, estamos atascados en un bucle infinito porque la actividad se recrearía directamente después de comenzar a escuchar LiveData.
Me resulta difícil creer que soy el primero que intenta actualizar las actividades desde la pila posterior después de cambiar el modo nocturno. ¿Qué me perdí?
¡Gracias!
Si puede detectar cuándo ha cambiado el modo día/noche, simplemente puede recrear una actividad que se reanuda cuando se abre la pila trasera.
En la siguiente demostración, hay tres actividades: A, B y C. A crea B y B crea C. La actividad C puede cambiar el modo día/noche. Cuando aparece C, la actividad B ve el cambio en el modo día/noche y llama a reCreate()
para recrear la actividad. Lo mismo sucede en la actividad A cuando se abre la actividad B.
El siguiente video muestra el efecto. El fondo de color claro es el modo "día" y el oscuro es el modo "noche".
Creé un proyecto de GitHub para esta aplicación de demostración. Si esto funciona como una solución, puedo incorporar más texto en la respuesta del proyecto.
Actualizar su back stack por completo probablemente sea excesivo y puede agregar algo de sobrecarga/retraso a la UX; y como mencionaste, la mayoría de las aplicaciones no tendrán acceso a un back stack estático completo.
Básicamente, está describiendo un problema más general: los cambios globales en el tema o en el propio WindowManager afectan el dibujo posterior de las vistas. Pero los diseños anteriores para las actividades en la pila no se pueden volver a dibujar. Puede parecer extraño para usted en esta situación, pero también podría haber muchas buenas razones por las que uno no querría volver a dibujar una actividad en la pila si una vez que el usuario vuelve a ella. Y entonces esta no es una característica automática.
Se me ocurren un par de opciones:
1) Escriba una clase personalizada heredada de Actividad que invalide todas sus vistas cuando se mueva al frente de la pila nuevamente. Por ejemplo, en onResume()
o onRestart()
, llame (si está en Fragment
)
View view = getActivity().findViewById(R.id.viewid); view.invalidate();
Utilice esta actividad personalizada para todas las actividades que desee mantener en consonancia con el modo diurno/nocturno actual.
2) Utilice ActivityLifecycleCallbacks
. Esto ayuda a mantener toda su lógica en un solo lugar y evita la necesidad de una herencia personalizada como se indicó anteriormente. Puede invalidar sus vistas aquí según sea necesario, ya que las actividades se pausan o reanudan. Podría incluir un Listener, si es su aplicación la que está cambiando el tema, y registrarlo como SharedPreference
, por ejemplo.
Para usar, agregue las devoluciones de llamada a su clase de aplicación:
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) { } });
Respuesta rápida:
@Override protected void onRestart() { super.onRestart(); recreate(); }
Agrega los códigos anteriores a su MainActivity y funcionará.