You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android 9中AppCompatDelegate.setDefaultNightMode不重建父Activity问题

解决Android 9+切换日夜主题后后台Activity不重建的问题

我之前也遇到过这个问题!Android 9(API 28)开始,系统对AppCompatDelegate.setDefaultNightMode()的行为做了调整——旧版本(API 27及以下)会重启所有已创建的Activity来应用新主题,但API 28+只会重建当前处于前台(resumed状态)的Activity,后台的Activity(比如你的Activity A)不会自动触发重建,这就是为什么你在Android 9上只看到Activity B变化的原因。

下面给你几个可行的解决方案:

方法一:通过广播触发所有Activity重建

这种方法比较灵活,适合有多个Activity的场景,我们可以通过发送自定义广播,让所有Activity收到后自行重建:

  1. 定义广播Action
// 可以放在你的工具类或者常量类中
public static final String ACTION_RECREATE_ACTIVITIES = "com.your.package.name.RECREATE_ACTIVITIES";
  1. 在BaseActivity中统一处理广播
    如果你的项目有BaseActivity,直接在里面注册广播接收器,所有继承它的Activity都会自动响应:
public class BaseActivity extends AppCompatActivity {
    private BroadcastReceiver recreateReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 注册广播接收器
        recreateReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                // 收到广播后重建当前Activity
                recreate();
            }
        };
        IntentFilter filter = new IntentFilter(ACTION_RECREATE_ACTIVITIES);
        registerReceiver(recreateReceiver, filter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 销毁时注销广播,避免内存泄漏
        if (recreateReceiver != null) {
            unregisterReceiver(recreateReceiver);
        }
    }
}
  1. 切换主题时发送广播
    修改你Activity B中的点击事件代码,在设置完主题后发送广播:
applyNight.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        isNight = !isNight;
        // 保存主题状态
        SharedPrefrencesMethods.savePreferences(this, getString(R.string.night_key), isNight);
        // 设置默认夜间模式
        AppCompatDelegate.setDefaultNightMode(isNight ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
        // 发送广播触发所有Activity重建
        Intent intent = new Intent(ACTION_RECREATE_ACTIVITIES);
        sendBroadcast(intent);
    }
});

方法二:通过Application监听所有Activity生命周期

这种方法可以直接管理所有已创建的Activity,一次性触发重建:

  1. 自定义Application类
public class MyApplication extends Application {
    // 存储所有已创建的Activity
    private final List<Activity> mActivityList = new ArrayList<>();

    @Override
    public void onCreate() {
        super.onCreate();
        // 注册Activity生命周期回调
        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
            @Override
            public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
                mActivityList.add(activity);
            }

            @Override
            public void onActivityDestroyed(@NonNull Activity activity) {
                mActivityList.remove(activity);
            }

            // 其他生命周期方法可以空实现
            @Override public void onActivityStarted(@NonNull Activity activity) {}
            @Override public void onActivityResumed(@NonNull Activity activity) {}
            @Override public void onActivityPaused(@NonNull Activity activity) {}
            @Override public void onActivityStopped(@NonNull Activity activity) {}
            @Override public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {}
        });
    }

    // 重建所有未销毁的Activity
    public void recreateAllActivities() {
        for (Activity activity : mActivityList) {
            if (!activity.isFinishing()) {
                activity.recreate();
            }
        }
    }
}

记得在AndroidManifest.xml中配置这个Application:

<application
    android:name=".MyApplication"
    ...>
    ...
</application>
  1. 调用重建方法
    在Activity B的点击事件中添加一行代码:
applyNight.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        isNight = !isNight;
        SharedPrefrencesMethods.savePreferences(this, getString(R.string.night_key), isNight);
        AppCompatDelegate.setDefaultNightMode(isNight ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO);
        // 触发全局Activity重建
        ((MyApplication) getApplication()).recreateAllActivities();
    }
});

方法三:在后台Activity的onResume中检查主题状态

如果只有少数几个后台Activity需要更新,这种方法更简单:
在Activity A的onResume()方法中,检查当前主题状态和实际设置是否一致,如果不一致就重建自己:

@Override
protected void onResume() {
    super.onResume();
    // 从SharedPreferences获取保存的主题状态
    boolean savedNightMode = SharedPrefrencesMethods.getBoolean(this, getString(R.string.night_key), false);
    // 获取当前App的默认夜间模式
    int currentAppNightMode = AppCompatDelegate.getDefaultNightMode();
    
    // 判断是否需要重建
    boolean needRecreate = (savedNightMode && currentAppNightMode != AppCompatDelegate.MODE_NIGHT_YES)
            || (!savedNightMode && currentAppNightMode != AppCompatDelegate.MODE_NIGHT_NO);
    
    if (needRecreate) {
        recreate();
    }
}

注意事项

  • 确保所有Activity都继承自AppCompatActivity,并且使用的是支持日夜切换的主题(比如Theme.MaterialComponents.DayNight.DarkActionBar或者Theme.AppCompat.DayNight.DarkActionBar),否则主题切换可能不生效。
  • 方法二中要注意Activity的添加和移除,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Radwa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 14:07:30