AppCompatDelegate.setDefaultNightMode() 仅在第一次被 main activity 拾取?
AppCompatDelegate.setDefaultNightMode() picked up by main activity only the first time?
运行 Android P
,使用 androidx 1.0.0
(minSdkVersion 17
)。从我的 MainActivity
打开我的 PreferenceActivity
。我在那里更改了 UI 主题,并重新创建了 activity 以获取更改:
AppCompatDelegate.setDefaultNightMode(nightMode);
recreate();
更新主题后,我return到MainActivity
。主题已成功更新。然后我重新打开 PreferenceActivity
并再次更改主题 。
目前一切顺利!
终于,我return又来了MainActivity
。主题未更新,重复步骤将不会更新!
因此,重现的步骤似乎是:
- 从activityA,打开activityB.
- 在B中调用
AppCompatDelegate.setDefaultNightMode(
MODE_NIGHT_YES)
然后调用recreate()
。主题已更新!
- Return to A.主题已更新!
- 再次打开activity B。
- 在B中调用
AppCompatDelegate.setDefaultNightMode(
MODE_NIGHT_NO)
然后调用recreate()
。主题已更新!
- Return 到 A。主题 未 已更新,如果重复步骤 3-6,将 未 更新!
我尝试在从 PreferenceActivity
返回时调用 recreate()
,但是当库 对主题更改做出反应时,这会产生另一个问题:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (...) {
recreate();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
当图书馆对更新的主题没有反应时,这会起作用。否则 activity 会被重新创建两次(调试时可能更多),这会降低性能等:
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
当您更改夜间模式时,将模式值存储到共享首选项中。
AppCompatDelegate.setDefaultNightMode(nightMode);
recreate(); //only recreate setting activity
...//store mode value, these lines are omitted,please complete yourself
在其他 activity onCreate() 方法中:
...//get mode from share preference, these lines are omitted.
AppCompatDelegate.setDefaultNightMode(mode)//must place before super.onCreate();
super.onCreate(savedInstanceState);
我找到了一个相当解决这个问题的简单方法。它在两种情况下都有效;当 AppCompatActivity
成功重新创建自己时 和 失败时。回想一下 activity A
在主题改变的地方调用 activity B
,然后我们在主题不总是更新的地方 return 到 A
。
Activity B
在 activity 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();
}
}
我们将这条信息提供给调用activity,即Main:
@Override
public void finish() {
Intent data = new Intent();
data.putExtra(EXTRA_THEME_CHANGED, mThemeChanged);
setResult(RESULT_OK, data);
super.finish();
}
Activity一个
然后在activityA
我们用到这条信息:
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()
我们的标志将被重置,避免在我们到达 [= 时重新创建 activity 21=]。因此,这段代码应该是面向未来的。不过,我真的希望这个问题在 androidx
的下一版本中得到解决,让我们摆脱解决方法。
更新
看起来这已在 AppCompat 1.1.0
中修复。我不再需要此解决方法来获得所需的行为。
运行 Android P
,使用 androidx 1.0.0
(minSdkVersion 17
)。从我的 MainActivity
打开我的 PreferenceActivity
。我在那里更改了 UI 主题,并重新创建了 activity 以获取更改:
AppCompatDelegate.setDefaultNightMode(nightMode);
recreate();
更新主题后,我return到MainActivity
。主题已成功更新。然后我重新打开 PreferenceActivity
并再次更改主题 。
目前一切顺利!
终于,我return又来了MainActivity
。主题未更新,重复步骤将不会更新!
因此,重现的步骤似乎是:
- 从activityA,打开activityB.
- 在B中调用
AppCompatDelegate.setDefaultNightMode(
MODE_NIGHT_YES)
然后调用recreate()
。主题已更新! - Return to A.主题已更新!
- 再次打开activity B。
- 在B中调用
AppCompatDelegate.setDefaultNightMode(
MODE_NIGHT_NO)
然后调用recreate()
。主题已更新! - Return 到 A。主题 未 已更新,如果重复步骤 3-6,将 未 更新!
我尝试在从 PreferenceActivity
返回时调用 recreate()
,但是当库 对主题更改做出反应时,这会产生另一个问题:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (...) {
recreate();
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
当图书馆对更新的主题没有反应时,这会起作用。否则 activity 会被重新创建两次(调试时可能更多),这会降低性能等:
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
当您更改夜间模式时,将模式值存储到共享首选项中。
AppCompatDelegate.setDefaultNightMode(nightMode);
recreate(); //only recreate setting activity
...//store mode value, these lines are omitted,please complete yourself
在其他 activity onCreate() 方法中:
...//get mode from share preference, these lines are omitted.
AppCompatDelegate.setDefaultNightMode(mode)//must place before super.onCreate();
super.onCreate(savedInstanceState);
我找到了一个相当解决这个问题的简单方法。它在两种情况下都有效;当 AppCompatActivity
成功重新创建自己时 和 失败时。回想一下 activity A
在主题改变的地方调用 activity B
,然后我们在主题不总是更新的地方 return 到 A
。
Activity B
在 activity 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();
}
}
我们将这条信息提供给调用activity,即Main:
@Override
public void finish() {
Intent data = new Intent();
data.putExtra(EXTRA_THEME_CHANGED, mThemeChanged);
setResult(RESULT_OK, data);
super.finish();
}
Activity一个
然后在activityA
我们用到这条信息:
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()
我们的标志将被重置,避免在我们到达 [= 时重新创建 activity 21=]。因此,这段代码应该是面向未来的。不过,我真的希望这个问题在 androidx
的下一版本中得到解决,让我们摆脱解决方法。
更新
看起来这已在 AppCompat 1.1.0
中修复。我不再需要此解决方法来获得所需的行为。