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

Android 10以下版本ClassCastException崩溃问题求助

Android 10以下版本SharedPreferences触发ClassCastException崩溃解决方案

问题描述

应用在Android 10以下版本频繁崩溃,崩溃提示:
Unable to start activity ComponentInfo{OnboardingActivity}: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Object[]

栈追踪信息:

Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Object[]
    android.util.ArrayMap.allocArrays(ArrayMap.java:213)
    android.util.ArrayMap.put(ArrayMap.java:499)
    android.app.ContextImpl.getSharedPreferences(ContextImpl.java:373)
    com.common.sale.base.CommonPreferences.<init>(CommonPreferences.java:6)
com.common.sale.base.BaseActivity.attachBaseContext(BaseActivity.kt:6)

上下文信息:OnboardingActivity继承自BaseActivity,CommonPreferences核心代码如下:

class CommonPreferences(context: Context) {

    private val SHARED_PREF_ADS: String = "common-project-shared-preference"
    private val sharedPreferences = context.getSharedPreferences(SHARED_PREF_ADS, Context.MODE_PRIVATE);
    private val sharedPreferenceChangeListener =
        SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
        }.also { sharedPreferences.registerOnSharedPreferenceChangeListener(it) }

    private val resources = context.resources

    private val isShowOnboardingKey
        get() = resources.getString(
            R.string.preferences_is_show_onboarding_key
        )
    var isShowOnboarding
        get() = sharedPreferences.getBoolean(isShowOnboardingKey, true)
        set(value) {
            sharedPreferences.edit().putBoolean(isShowOnboardingKey, value).apply()
        }

    private val appLanguageKey
        get() = resources.getString(
            R.string.preferences_app_language_key
        )
    var appLanguage
        get() = sharedPreferences.getString(appLanguageKey, "")
        set(value) {
            sharedPreferences.edit().putString(appLanguageKey, value).apply()
        }
}

崩溃原因

该问题是Android 10及以下版本的系统bug:SharedPreferences内部存储文件损坏,导致ArrayMap解析键值对时,将本应是数组结构的数据错误识别为String,触发强制类型转换失败。

解决方案

1. 主动检测并修复损坏的SharedPreferences文件

在初始化CommonPreferences前,提前尝试获取SharedPreferences并捕获异常,一旦触发ClassCastException就删除损坏的文件,让系统重新生成:

// 修改BaseActivity的attachBaseContext方法
override fun attachBaseContext(newBase: Context?) {
    super.attachBaseContext(newBase)
    newBase?.let { ctx ->
        val prefName = "common-project-shared-preference"
        try {
            // 提前触发可能的异常
            ctx.getSharedPreferences(prefName, Context.MODE_PRIVATE)
        } catch (e: ClassCastException) {
            // 删除损坏的文件
            ctx.deleteSharedPreferences(prefName)
        }
        // 正常初始化CommonPreferences
        CommonPreferences(ctx)
    }
}

2. 延迟SharedPreferences初始化时机

attachBaseContext是Context初始化的早期阶段,部分系统资源未完全就绪,建议将CommonPreferences的初始化延迟到onCreate方法中:

// BaseActivity中调整初始化逻辑
lateinit var commonPrefs: CommonPreferences

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    commonPrefs = CommonPreferences(this)
}

3. 优化SharedPreferences写入操作

确保写入操作的原子性,避免多线程同时写入导致文件损坏:

  • 如果不需要异步写入,改用commit()替代apply()(commit()是同步操作,保证原子性)
  • 若必须使用apply(),确保所有写入调用在同一线程,或通过锁保证线程安全
// 示例:使用commit()保证原子性
sharedPreferences.edit().putBoolean(isShowOnboardingKey, value).commit()

4. 清理旧的损坏缓存

针对Android 10及以下版本,在应用启动时主动检查SharedPreferences文件完整性,发现异常直接删除,避免重复崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 19:36:10