6

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

假设我有后台A > B > C。Activity C 允许通过调用来改变夜间模式AppCompatDelegate.setDefaultNightMode()。在此调用之后,当前 Activity (C) 可以使用delegate.applyDayNight()或刷新其主题recreate()

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

我试图在活动中添加类似的东西:

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

但这似乎不起作用。

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

一个想法是完全按照此处此处的建议重新创建后台堆栈,但是由于后台堆栈不是静态的,因此对我来说不可行。

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

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

谢谢!

4

4 回答 4

14

如果您可以检测到白天/夜间模式何时发生变化,您可以简单地重新创建一个在弹出返回堆栈时恢复的活动。

在下面的演示中,共有三个活动:A、B 和 C。A 创建 B,B 创建 C。活动 C 可以更改昼夜模式。当 C 被弹出时,活动 B 看到日/夜模式的变化并调用reCreate()以重新创建活动。当活动 B 弹出时,活动 A 中也会发生同样的情况。

下面的视频展示了效果。浅色背景为“白天”模式,深色为“夜间”模式。

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

在此处输入图像描述

于 2019-03-11T01:26:42.190 回答
1

快速回答:

    @Override
    protected void onRestart() {
        super.onRestart();

        recreate();
    }

您将上述代码添加到您的 MainActivity 中,它将起作用。

于 2020-03-11T19:56:44.907 回答
0

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

于 2019-03-07T05:41:44.393 回答
0

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

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

我可以想到几个选项:

1)编写一个继承自 Activity 的自定义类,当它再次移动到堆栈的前面时,它的所有视图都将失效。例如 in onResume()or onRestart(), call (if in Fragment)

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

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

2)使用ActivityLifecycleCallbacks。这有助于将所有逻辑保存在一个地方,并避免需要如上所述的自定义继承。当活动暂停/恢复时,您可以根据需要在此处使您的视图无效。例如,如果是您的应用程序正在更改主题,您可以包含一个 Listener,并记录为SharedPreference

要使用,请将回调添加到您的 Application 类:

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) {
    }
});
于 2019-03-11T12:33:07.047 回答