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

Android切换深浅色模式报ClassCastException且退出后模式状态丢失

Android深色模式切换异常与状态丢失修复

现存问题

  • 点击深色模式切换按钮时,浅色到深色的切换效果可正常生效,但会抛出运行时异常
  • 退出应用(进程被杀)后,已设置的深色模式自动失效,默认切回浅色模式

原有实现代码

binding.darkModeBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked){
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            }else{
                AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
            }
        }
    });

报错日志

E/ActivityInjector: get life cycle exception
java.lang.ClassCastException: android.os.BinderProxy cannot be cast to android.app.servertransaction.ClientTransaction
    at android.app.ActivityInjector.checkAccessControl(ActivityInjector.java:24)
    at android.app.Activity.onResume(Activity.java:2011)
    at androidx.fragment.app.FragmentActivity.onResume(FragmentActivity.java:434)
    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1456)
    at android.app.Activity.performResume(Activity.java:8297)
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4591)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4633)
    at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
    at android.app.ClientTransactionHandler.executeTransaction(ClientTransactionHandler.java:58)
    at android.app.ActivityThread.handleRelaunchActivityLocally(ActivityThread.java:5595)
    at android.app.ActivityThread.access$3600(ActivityThread.java:263)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2197)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:236)
    at android.app.ActivityThread.main(ActivityThread.java:8057)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:620)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1011)

问题根因

  • 运行时异常:调用AppCompatDelegate.setDefaultNightMode()后系统会自动触发Activity本地重建,部分定制ROM(日志中带ActivityInjector的国产定制系统)修改了原生Activity重建流程,在本地重建逻辑中存在类型转换bug,触发系统级异常,该异常并非业务代码语法错误导致。
  • 重启失效:AppCompatDelegate.setDefaultNightMode()的配置仅在当前应用进程生命周期内生效,没有做持久化存储,进程被杀重启后会默认加载系统主题配置,自动回到浅色模式。

修复方案

  • 新增主题配置持久化逻辑
    切换主题时将选中的模式存入SharedPreferences,避免进程重启后配置丢失:
binding.darkModeBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        int targetMode = isChecked ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO;
        // 持久化存储主题配置
        getSharedPreferences("app_config", MODE_PRIVATE)
                .edit()
                .putInt("key_night_mode", targetMode)
                .apply();
        AppCompatDelegate.setDefaultNightMode(targetMode);
    }
});
  • 应用启动时提前加载主题配置
    在自定义Application的onCreate方法中读取已存储的主题配置,在所有Activity创建前完成主题设置,避免启动时闪浅色:
public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // 提前读取存储的主题配置
        int savedMode = getSharedPreferences("app_config", MODE_PRIVATE)
                .getInt("key_night_mode", AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
        AppCompatDelegate.setDefaultNightMode(savedMode);
    }
}

需要在AndroidManifest.xml的application标签下配置name属性,指向自定义的BaseApplication类

  • 手动控制Activity重建时机绕开系统bug
    给切换按钮增加初始化状态判断,跳过页面首次加载时触发的默认回调,同时在设置主题后手动调用recreate()重建页面,避开系统自动重建流程的ROM bug:
binding.darkModeBtn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
    // 标记是否为初始化阶段,避免首次进入页面触发不必要的重建
    private boolean isInitializing = true;
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isInitializing) {
            isInitializing = false;
            return;
        }
        int targetMode = isChecked ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO;
        getSharedPreferences("app_config", MODE_PRIVATE)
                .edit()
                .putInt("key_night_mode", targetMode)
                .apply();
        AppCompatDelegate.setDefaultNightMode(targetMode);
        // 延迟到视图状态更新完成后手动重建,避开系统本地重建的异常逻辑
        buttonView.post(() -> recreate());
    }
});

多Activity架构建议在基类Activity的onCreate阶段增加主题一致性校验,如果当前页面主题和存储的配置不一致,及时调整避免页面主题错乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 14:48:15