使用Android P
(androidx 1.0.0
)运行minSdkVersion 17
。从我的MainActivity
中打开我的PreferenceActivity
。在那里,我更改了UI主题,还重新创建了活动以获取更改:
AppCompatDelegate.setDefaultNightMode(nightMode);
recreate();
更新主题之后,我返回到MainActivity
。在那里,主题已成功更新。然后,我重新打开PreferenceActivity
并再次更改主题 。
到目前为止一切顺利!
最后,我再次回到MainActivity
。主题已未更新,并且如果您重复这些步骤,它将不会更新!
因此,重现步骤似乎是:
AppCompatDelegate.setDefaultNightMode(
MODE_NIGHT_YES )
,然后致电recreate()
。主题已更新!AppCompatDelegate.setDefaultNightMode(
MODE_NIGHT_NO )
,然后致电recreate()
。主题已更新!我尝试从recreate()
重新调用时调用PreferenceActivity
,但是当库确实对主题更改做出反应时,这又产生了另一个问题:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (...) {
recreate();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
当库对更新后的主题不起作用时,该方法有效。否则,该活动将被重新创建两次(调试时可能会重新创建两次),这会降低性能,等等:
D/MainActivity: onActivityResult(): instance 1
D/MainActivity: onResume(): instance 1
D/MainActivity: onPause(): instance 1
D/MainActivity: onDestroy(): instance 1
D/MainActivity: onCreate(): instance 2
D/MainActivity: onResume(): instance 2
D/MainActivity: onPause(): instance 2
D/MainActivity: onDestroy(): instance 2
D/MainActivity: onCreate(): instance 3
D/MainActivity: onResume(): instance 3
问::setDefaultNightMode()
API发生了什么?更重要的是,如何才能成功更新所有正在运行的活动,而又无需多次重新创建它们?
这里有一个示例项目演示了这个问题:https://issuetracker.google.com/issues/119757688
答案 0 :(得分:0)
更改夜间模式时,将模式值存储为共享首选项。
AppCompatDelegate.setDefaultNightMode(nightMode);
recreate(); //only recreate setting activity
...//store mode value, these lines are omitted,please complete yourself
在其他活动的onCreate()方法中:
...//get mode from share preference, these lines are omitted.
AppCompatDelegate.setDefaultNightMode(mode)//must place before super.onCreate();
super.onCreate(savedInstanceState);
答案 1 :(得分:0)
我找到了一个解决该问题的简单方法。它在两种情况下都有效; AppCompatActivity
成功地重新创建自身 时以及失败时。回想一下活动A
调用了活动B
,其中主题已更改,然后我们返回到A
,主题并不总是更新。
在活动B
中-即首选项-我们跟踪主题更改:
private boolean mThemeChanged;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mThemeChanged = getIntent().getBooleanExtra(EXTRA_THEME_CHANGED, false);
}
private void onNightModeChanged() {
int nightMode = getNightModeFromPreferences();
if (AppCompatDelegate.getDefaultNightMode() != nightMode) {
AppCompatDelegate.setDefaultNightMode(nightMode);
getIntent().putExtra(EXTRA_THEME_CHANGED, true);
getDelegate().applyDayNight();
}
}
我们将这些信息提供给呼叫活动,即Main:
@Override
public void finish() {
Intent data = new Intent();
data.putExtra(EXTRA_THEME_CHANGED, mThemeChanged);
setResult(RESULT_OK, data);
super.finish();
}
然后在活动A
中,我们使用以下信息:
private boolean mShouldRecreateActivity;
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ActivityResults.OPEN_SETTINGS_RESULT) {
if (data != null && data.getBooleanExtra(SetPreferenceActivity.EXTRA_THEME_CHANGED, false)) {
mShouldRecreateActivity = true;
}
}
}
@Override
protected void onResume() {
super.onResume();
if (mShouldRecreateActivity) {
recreate();
return; // No need to continue resuming!
}
}
@Override
public void recreate() {
super.recreate();
mShouldRecreateActivity = false;
}
在极少数情况下(通常是第一次),AppCompatActivity
正确调用recreate()
时,我们的标志将被重置,从而避免在到达onResume()
时再次进行活动。因此,该代码应该是面向未来的。但是,我真的希望在下一版androidx
中解决此问题,让我们摆脱此变通办法。