代码之家  ›  专栏  ›  技术社区  ›  l33t

只有第一次被主活动获取的appcompatDelegate.setDefaultNightMode()?

  •  2
  • l33t  · 技术社区  · 7 年前

    运行 Android P ,使用 androidx 1.0.0 ( minSdkVersion 17 )从我 MainActivity 我打开我的门 PreferenceActivity . 在这里,我更改了UI主题,还重新创建了活动来获取更改:

    AppCompatDelegate.setDefaultNightMode(nightMode);
    recreate();
    

    更新主题后,我返回 主要活动 . 主题已成功更新。然后我重新打开 首选项活动 改变主题 再一次 .

    到现在为止,一直都还不错!

    最后,我回到 主要活动 再一次。主题是 不是 更新,如果您重复这些步骤,它将不会更新!

    因此,复制的步骤似乎是:

    1. 从活动A打开活动B。
    2. 在B中,调用 AppCompatDelegate.setDefaultNightMode( 莫迪夜莺 ) 然后 recreate() . 主题已更新!
    3. 返回A。主题已更新!
    4. 再次打开活动B。
    5. 在B中,呼叫 AppCompatDelegate.setDefaultNightMode( 夜行之夜 ) 然后 重新创建() . 主题已更新!
    6. 回到A。主题是 不是 更新并将 不是 如果重复步骤3-6,则更新!

    我试着打电话 重新创建() 当从 首选项活动 但当图书馆 对主题变化做出反应:

    @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() 应用程序编程接口?更重要的是,我如何才能成功地更新所有正在运行的活动,而不存在多次重新创建这些活动的风险?

    更新

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

    2 回复  |  直到 7 年前
        1
  •  0
  •   navylover    7 年前

    更改夜间模式时,将模式值存储为共享首选项。

    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);
    
        2
  •  0
  •   l33t    7 年前

    我找到了一个 相当地 这个问题的简单解决方案。在这两种情况下都有效;当 AppCompatActivity 成功地重新创建了自己 当它不能做到的时候。回忆一下那个活动 A 通话活动 B 如果主题发生了变化,那么我们将返回 主题不总是更新的地方。

    活动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();
        }
    }
    

    我们向呼叫活动提供这一信息,即主:

    @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;
    }
    

    在罕见的情况下(通常是第一次) 应用程序兼容性 正确调用 recreate() 我们的旗子将被重置,避免在我们到达时对活动进行额外的娱乐。 onResume() . 因此,此代码 应该是未来的证据 . 不过,我真的希望这个问题在下一个版本的 androidx 让我们摆脱工作区。