夜间模式更改后刷新后台活动

Refresh the backstack Activities after Night Mode has changed

我看到很多关于在更改应用程序的夜间模式后重新创建当前 activity 的问题和答案,但我没有看到任何关于如何刷新后台堆栈活动的内容。

假设我有后台堆栈 A > B > C。 Activity C 允许通过调用 AppCompatDelegate.setDefaultNightMode() 更改夜间模式。此调用后,当前 Activity (C),可以用 delegate.applyDayNight()recreate().

刷新其主题

但是,当用户导航回 B 或 A 时,活动仍在使用 "old" 模式,无论是白天还是晚上。

我试图将类似的内容添加到活动中:

override fun onResume() {
  super.onResume()
  delegate.applyDayNight()
}

但是好像不行。

我多次尝试解决这个问题:

一个想法是像建议的那样完全重新创建 backstack here or here,但是由于 backstack 不是静态的,它对我来说不可行。

另一个想法是 class 处理夜间模式变化并提供 LiveData。每个 Activity 都会监听 LiveData 以获取模式更改并调用 recreate()。但是,我们陷入了无限循环,因为 Activity 会在开始收听 LiveData 后直接重新创建。

我很难相信我是第一个尝试在更改夜间模式后从后台刷新活动的人。我错过了什么?

谢谢!

在项目中创建一个静态布尔变量,并在每个 activity 中检查布尔值是真还是假,然后根据值应用日光和夜晚。

如果您可以检测到 day/night 模式何时更改,您可以简单地重新创建一个 activity,当返回堆栈被弹出时它会恢复。

下面的demo中,有A、B、C三个Activity,A创建B,B创建C。ActivityC可以改变day/night模式。当 C 弹出时,activity B 看到 day/night 模式的变化并调用 reCreate() 重新创建 activity。当弹出 activity B 时,activity A 也会发生同样的情况。

下面的视频展示了效果。浅色背景为"day"模式,深色背景为"night"模式。

我已经为这个演示应用程序创建了一个 GitHub project。如果这可以作为解决方案,我可以将更多文本合并到项目的答案中。

完全刷新你的后台堆栈可能有点矫枉过正,可能会给用户体验增加一些 overhead/lag;正如您所提到的,大多数应用程序将无法访问完整的静态返回堆栈。

您本质上是在描述一个更普遍的问题:主题或 WindowManager 本身的全局更改会影响后续的视图绘制。但是堆栈中 Activity 的先前布局可能不会重绘。在这种情况下,这对您来说可能看起来很奇怪,但是也有很多很好的理由可以说明为什么一旦用户返回它就不想在堆栈中重新绘制 Activity 。所以这不是自动功能。

我可以想到几个选项:

1) 编写一个继承自 Activity 的自定义 class,当它再次移动到堆栈的前面时,它会使其所有视图无效。例如。在 onResume()onRestart() 中,调用(如果在 Fragment 中)

View view = getActivity().findViewById(R.id.viewid);
view.invalidate();

将此自定义 Activity 用于您希望与当前 day/night 模式保持一致的所有活动。

2) 使用ActivityLifecycleCallbacks。这有助于将所有逻辑放在一个地方,并避免需要如上所述的自定义继承。您可以根据需要在此处使您的观点无效,因为活动 paused/resumed。例如,如果是您的应用正在更改主题,您可以包含一个监听器,并记录为 SharedPreference

要使用,请将回调添加到您的应用程序 class:

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 中,它会起作用。