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

Kotlin开发SharedPreference初始化后部分用户触发未初始化异常崩溃

问题原因
  • ContentProvider提前访问:Android系统中,ContentProvider的初始化时机早于Application的onCreate回调。如果你的项目中集成的第三方SDK、或者自定义的ContentProvider在初始化阶段就访问了PreferenceUtil的属性,此时init方法还未执行,就会触发未初始化异常。
  • 并发访问竞态条件:init方法中的isInitialized判断和mPref赋值不是原子操作,也没有加同步锁。如果在应用启动阶段有多个线程同时触发init调用,或者在init执行完成前就有其他线程访问mPref相关属性,就会出现判断已经通过但赋值还未完成的情况,触发异常。
  • 特殊进程/ROM异常:如果应用配置了多进程,部分特殊进程的初始化流程被厂商ROM篡改,或者你做了进程区分的初始化逻辑跳过了PreferenceUtil的初始化,也会出现该问题。
解决方法

方案1:懒加载初始化(最稳妥,可省略手动init步骤)

直接将mPref修改为懒加载模式,自动获取ApplicationContext,完全避免手动初始化的时序问题:

// 先在Application中提供全局ApplicationContext入口
class MyApplication : Application() {
    companion object {
        lateinit var appContext: Context
            private set
    }
    override fun onCreate() {
        super.onCreate()
        appContext = this.applicationContext
    }
}

// PreferenceUtil修改为自动初始化
object PreferenceUtil {
    private val mPref: SharedPreferences by lazy { 
        PreferenceManager.getDefaultSharedPreferences(MyApplication.appContext) 
    }
    
    // 其余属性读写逻辑不变
    var launchCount: Int
        get() = mPref.getInt("launch_count", 0)
        set(value) = mPref.edit().putInt("launch_count", value).apply()
}

方案2:修复原有init逻辑的线程安全问题

如果要保留原有的手动init设计,修改init方法为线程安全,同时排查所有ContentProvider逻辑,禁止在ContentProvider中访问PreferenceUtil:

object PreferenceUtil {
    private lateinit var mPref: SharedPreferences

    @Synchronized // 加同步锁保证原子性
    fun init(context: Context) {
        if (!this::mPref.isInitialized) {
            mPref = PreferenceManager.getDefaultSharedPreferences(context.applicationContext)
        }
    }
}

方案3:访问时兜底初始化

在所有读写mPref的属性中加入初始化检查,发现未初始化时主动触发初始化,作为兜底方案:

var launchCount: Int
    get() {
        if (!this::mPref.isInitialized) {
            init(MyApplication.appContext)
        }
        return mPref.getInt("launch_count", 0)
    }
    set(value) {
        if (!this::mPref.isInitialized) {
            init(MyApplication.appContext)
        }
        mPref.edit().putInt("launch_count", value).apply()
    }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 11:06:03