Android 8.0多线程切换主题正常,Android 11崩溃求助
问题分析与修复方案
崩溃原因
AppCompatDelegate.setDefaultNightMode() 是涉及UI配置变更的操作,必须在主线程执行。Android 11 对主线程操作的校验机制更严格,子线程调用该方法会直接触发崩溃;而 Android 8.0 系统的校验逻辑较宽松,所以没暴露这个问题。另外,子线程中调用 getString()(依赖Context实例)也存在潜在的线程安全风险。
修复代码
把主题切换和SharedPreferences操作全部移回主线程,同时优化代码逻辑:
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); String[] themeStrings = {"Light","Dark","System Default"}; ListView lv = requireView().findViewById(R.id.themeChangeLV); ArrayAdapter<String> ad = new ArrayAdapter<>(requireContext(), android.R.layout.simple_list_item_1,themeStrings); lv.setAdapter(ad); sharedPreferences = requireContext().getSharedPreferences("MODE", Context.MODE_PRIVATE); nightMODE = sharedPreferences.getBoolean("night",false); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { SharedPreferences.Editor editor = sharedPreferences.edit(); switch (i){ case 0: AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); editor.putBoolean(getString(R.string.night),false); editor.putBoolean(getString(R.string.sdt),false); editor.apply(); break; case 1: AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); editor.putBoolean(getString(R.string.night),true); editor.putBoolean(getString(R.string.sdt),false); editor.apply(); break; case 2: editor.putBoolean(getString(R.string.sdt),true); editor.apply(); AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); break; } // 可选:添加平滑过渡减少黑屏感 if (getActivity() != null) { getActivity().overridePendingTransition(0, 0); getActivity().recreate(); getActivity().overridePendingTransition(0, 0); } } }); }
关键修改点
- 移除所有子线程逻辑,将
setDefaultNightMode()和SP编辑操作移至主线程执行 - 每次点击时重新获取
SharedPreferences.Editor,避免复用导致的线程安全问题 - 补充了"System Default"对应的主题模式设置(原代码漏了这一步)
- 可选添加
overridePendingTransition(0,0)来减少重建Activity时的黑屏闪烁感
额外说明
如果想要进一步优化主题切换的流畅度,可以考虑:
- 使用
ViewModel保存当前页面状态,避免重建后数据丢失 - 为Activity设置主题切换的过渡动画,替代无动画的重建
内容的提问来源于stack exchange,提问作者Arya_
相关产品推荐
相关产品推荐

