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收到后自行重建:
- 定义广播Action
// 可以放在你的工具类或者常量类中 public static final String ACTION_RECREATE_ACTIVITIES = "com.your.package.name.RECREATE_ACTIVITIES";
- 在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); } } }
- 切换主题时发送广播
修改你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,一次性触发重建:
- 自定义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>
- 调用重建方法
在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
相关产品推荐
相关产品推荐

