【问题标题】:AppCompatDelegate.setDefaultNightMode() picked up by main activity only the first time?AppCompatDelegate.setDefaultNightMode() 仅第一次被主要活动拾取?
【发布时间】:2018-11-17 23:48:37
【问题描述】:

运行Android P,使用androidx 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,将更新!

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

@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

【问题讨论】:

  • 有什么解决办法吗?我也遇到了同样的问题。
  • 当然。你看到我的回答了吗?
  • 其实我在其他地方发现了这个问题(WebView bug);见this answer
  • 有趣。很明显,切换夜间模式仍然容易出错。
  • 示例项目不会为我运行,它说主题是错误的。我认为您在项目的 res 中遗漏了文件。

标签: android androidx


【解决方案1】:

当您更改夜间模式时,将模式值存储到共享偏好中。

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);

【讨论】:

  • 从设置活动返回时,onCreate 不会被调用(除非我重新创建活动)。 setDefaultNightMode 方法在应用程序启动时被调用。一切正常,除了主题更新机制在运行一次后似乎中断。我相信 Android 源代码中的 this flag 可能是罪魁祸首。
【解决方案2】:

我找到了一个相当简单的方法来解决这个问题。它适用于两种情况;当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 的下一版本中得到解决,让我们摆脱解决方法。

更新

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-02
    • 2012-03-25
    • 2012-01-04
    • 1970-01-01
    相关资源
    最近更新 更多