在更改应用程序的夜间模式后,我已经看到了很多关于重新创建当前活动的问题和答案,但我没有看到如何刷新后台堆栈活动。
假设我有后退A> B> C.活动C允许通过调用AppCompatDelegate.setDefaultNightMode()
来改变夜间模式。在此调用之后,当前活动(C)可以使用delegate.applyDayNight()
或recreate()
刷新其主题。
但是,当用户导航回B或A时,活动仍然使用“旧”模式,白天或晚上。
我试图在活动中添加类似的内容:
override fun onResume() {
super.onResume()
delegate.applyDayNight()
}
但它似乎没有用。
我做了多次尝试来解决这个问题:
一个想法是完全重建背板,就像建议的here或here,但由于背板不是静态的,它对我来说是不可行的。
另一个想法是有一个类来处理夜间模式更改并提供LiveData。每个Activity都会监听LiveData以进行模式更改并调用recreate()
。但是,我们陷入无限循环,因为Activity会在开始监听LiveData后直接重新创建。
我发现很难相信我是第一个在改变夜晚模式后试图从后台更新活动的人。我错过了什么?
谢谢!
如果您可以检测日/夜模式何时更改,则只需重新创建在弹出后堆栈时恢复的活动。
在下面的演示中,有三个活动:A,B和C.A创建B和B创建C.活动C可以更改日/夜模式。当弹出C时,活动B看到日/夜模式的变化,并调用reCreate()
重新创建活动。弹出活动B时,活动A也会发生同样的情况。
下面的视频显示了效果。浅色背景是“日”模式,黑暗是“夜晚”模式。
我为这个演示应用程序创建了一个GitHub project。如果这可以作为解决方案,我可以在项目的答案中加入更多文本。
在项目中创建一个静态布尔变量,并在每个活动中检查布尔值是真还是假,然后根据值应用日光和夜晚。
完全刷新你的后台可能是一种过度杀伤,可能会给UX带来一些开销/滞后;正如您所提到的,大多数应用程序无法访问完整的静态后台堆栈。
您实际上是在描述一个更普遍的问题:对主题的全局更改或WindowManager本身会影响后续的视图绘制。但是堆栈中活动的先前布局可能无法重绘。在这种情况下,你可能看起来很奇怪,但是如果一旦用户返回它,也可能有很多很好的理由让人们不想在堆栈中重绘一个Activity。所以这不是一个自动功能。
我可以想到几个选择:
1)编写一个继承自Activity的自定义类,当它再次移动到堆栈的前面时,它会使所有的视图无效。例如。在onResume()
或onRestart()
,致电(如果在Fragment
)
View view = getActivity().findViewById(R.id.viewid);
view.invalidate();
将此自定义活动用于您希望与当前日/夜模式保持一致的所有活动。
2)使用ActivityLifecycleCallbacks
。这有助于将所有逻辑保存在一个位置,并避免了如上所述的自定义继承。当活动暂停/恢复时,您可以根据需要在此处使您的视图无效。例如,如果您的应用程序正在更改主题,则可以包含一个监听器,并记录为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) {
}
});