AppCompatDelegate.setDefaultNightMode()是第一次由主要活动拾取的?

时间:2018-11-17 23:48:37

标签: android androidx

使用Android Pandroidx 1.0.0)运行minSdkVersion 17。从我的MainActivity中打开我的PreferenceActivity。在那里,我更改了UI主题,还重新创建了活动以获取更改:

AppCompatDelegate.setDefaultNightMode(nightMode);
recreate();

更新主题之后,我返回到MainActivity。在那里,主题已成功更新。然后,我重新打开PreferenceActivity并再次更改主题

到目前为止一切顺利!

最后,我再次回到MainActivity。主题已更新,并且如果您重复这些步骤,它将不会更新!

因此,重现步骤似乎是:

  1. 从活动A中打开活动B。
  2. 在B中,致电AppCompatDelegate.setDefaultNightMode( MODE_NIGHT_YES ),然后致电recreate()。主题已更新!
  3. 返回A。主题已更新!
  4. 再次打开活动B。
  5. 在B中,致电AppCompatDelegate.setDefaultNightMode( MODE_NIGHT_NO ),然后致电recreate()。主题已更新!
  6. 返回A。主题已更新,并且如果重复步骤3-6,将更新!

我尝试从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

2 个答案:

答案 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

在活动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

然后在活动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中解决此问题,让我们摆脱此变通办法。