AppCompatDelegate.setDefaultNightMode() 仅在第一次被主要活动拾取? [英] AppCompatDelegate.setDefaultNightMode() picked up by main activity only the first time?

查看:184
本文介绍了AppCompatDelegate.setDefaultNightMode() 仅在第一次被主要活动拾取?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

运行 Android P,使用 androidx 1.0.0 (minSdkVersion 17).从我的 MainActivity 打开我的 PreferenceActivity.在那里,我更改了 UI 主题,并重新创建了 Activity 以获取更改:

Running Android P, using androidx 1.0.0 (minSdkVersion 17). From my MainActivity I open my PreferenceActivity. There I change the UI theme, and also re-create the activity to pick up the changes:

AppCompatDelegate.setDefaultNightMode(nightMode);
recreate();

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

After updating the theme, I return to MainActivity. There the theme is successfully updated. Then I re-open the PreferenceActivity and change the theme again.

到目前为止一切都很好!

最后,我再次回到MainActivity.主题更新,重复步骤不会更新!

Finally, I return to the MainActivity again. The theme is NOT updated, and it will not update if you repeat the steps!

因此,重现的步骤似乎是:

  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,主题将更新!
  1. From activity A, open activity B.
  2. In B, call AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_YES) and then recreate(). Theme is updated!
  3. Return to A. Theme is updated!
  4. Open activity B again.
  5. In B, call AppCompatDelegate.setDefaultNightMode(MODE_NIGHT_NO) and then recreate(). Theme is updated!
  6. Return to A. Theme is NOT updated and will NOT update if steps 3-6 are repeated!

我尝试在从 PreferenceActivity 返回时调用 recreate() 但是当库确实对主题更改做出反应时,会产生另一个问题:

I tried calling recreate() when returing from the PreferenceActivity but that yields another problem when the library does react on the theme change:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (...) {
        recreate();
    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}

当图书馆对更新的主题没有反应时,这有效.否则,活动将重新创建两次(调试时可能更多),这会降低性能等:

That works when the library does NOT react on the updated theme. Otherwise the activity is recreated twice (possibly more when debugging), which kills performance etc:

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 发生了什么?更重要的是,我如何才能成功更新所有正在运行的活动,而又不存在多次重新创建活动的风险?

Q: What is going on with the setDefaultNightMode() API? And more importantly, how can I successfully update all running activities without the risk of re-creating them multiple times?

这里有一个示例项目演示了这个问题:https://issuetracker.google.com/issues/119757688

There is a sample project demonstrating the issue here: https://issuetracker.google.com/issues/119757688

推荐答案

我找到了一个相当简单的解决方案来解决这个问题.它适用于两种情况;当 AppCompatActivity 成功重新创建自身 失败时.回想一下,活动 A 调用活动 B,其中主题已更改,然后我们返回 A,其中主题并不总是更新.

I found a quite simple solution to this problem. It works in both cases; when AppCompatActivity successfully recreates itself and when it fails to do so. Recall that activity A calls activity B where the theme is changed, then we return to A where the theme is not always updated.

在活动 B - 即首选项 - 我们跟踪主题变化:

In activity B - i.e. Preferences - we keep track of theme changes:

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:

And we provide this piece of information to the calling activity, i.e. Main:

@Override
public void finish() {
    Intent data = new Intent();
    data.putExtra(EXTRA_THEME_CHANGED, mThemeChanged);
    setResult(RESULT_OK, data);

    super.finish();
}

活动 A

然后在活动 A 中我们使用这条信息:

Activity A

Then in activity A we use this piece of information:

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 的下一版本中得到解决,让我们摆脱解决方法.

In the rare case (usually the first time) the AppCompatActivity correctly calls recreate() our flag will be reset, avoiding an additional recreation of the activity when we reach onResume(). Thus, this code should be future-proof. Though, I really hope the issue is fixed in the next version of androidx, allowing us to get rid of the workaround.

看起来这已在 AppCompat 1.1.0 中修复.我不再需要此解决方法来获得所需的行为.

Looks like this was fixed in AppCompat 1.1.0. I no longer need this workaround to get the desired behavior.

这篇关于AppCompatDelegate.setDefaultNightMode() 仅在第一次被主要活动拾取?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆