如何在应用完全关闭而非转入后台时使用SharedPreferences存储数据?
解决方案:区分应用后台切换与完全关闭时的数据存储
嘿,这个问题我之前做应用的时候也踩过坑!确实,onPause()和onStop()触发太频繁了,切个后台就跑,根本没法区分用户是暂时切换应用还是真的要完全关掉它。下面给你几个亲测好用的方案:
1. 监听主动关闭事件:onTaskRemoved()
这个方法简直是为用户主动关闭App量身定做的!当用户从最近任务列表里把你的App划掉时,系统会调用Service中的onTaskRemoved()方法,完美匹配你要的「完全关闭」场景:
- 写一个轻量的服务(Android 8.0+建议用前台服务,避免被系统限制),重写该方法:
class AppCloseMonitorService : Service() { override fun onBind(intent: Intent?): IBinder? = null override fun onTaskRemoved(rootIntent: Intent?) { super.onTaskRemoved(rootIntent) // 在这里完成SharedPreferences数据存储 val sharedPref = getSharedPreferences("app_data", Context.MODE_PRIVATE) with(sharedPref.edit()) { putString("user_preference", "your_value") apply() // 用apply()异步写入,系统会兜底完成,比commit()更安全 } stopSelf() // 任务完成后停止服务 } }
- 在主Activity的
onCreate()里启动这个服务:
startService(Intent(this, AppCloseMonitorService::class.java))
如果是前台服务,只需要加个透明通知就行,用户几乎感知不到。
2. 统计活跃Activity数量,判断真正退出
通过Application.ActivityLifecycleCallbacks监听所有Activity的生命周期,统计当前活跃的Activity数量。当数量归0且一段时间内没有新Activity启动,就判定为完全关闭:
- 自定义Application类,注册生命周期回调:
class MyApp : Application() { private var activeActivityCount = 0 private var isAppInBackground = false override fun onCreate() { super.onCreate() registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { activeActivityCount++ } override fun onActivityStarted(activity: Activity) { activeActivityCount++ isAppInBackground = false } override fun onActivityStopped(activity: Activity) { activeActivityCount-- if (activeActivityCount == 0) { isAppInBackground = true // 延迟3秒检查,避免把后台切换误判为完全关闭 Handler(Looper.getMainLooper()).postDelayed({ if (activeActivityCount == 0 && isAppInBackground) { // 执行数据存储逻辑 val sharedPref = getSharedPreferences("app_data", Context.MODE_PRIVATE) with(sharedPref.edit()) { putString("user_preference", "your_value") apply() } } }, 3000) } } // 其他生命周期方法可空实现 override fun onActivityResumed(activity: Activity) {} override fun onActivityPaused(activity: Activity) {} override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) {} override fun onActivityDestroyed(activity: Activity) {} }) } }
这个方案不需要依赖Service,适合不想加服务的场景,延迟时间可以根据你的需求调整。
3. 结合ProcessLifecycleOwner监听进程状态
如果你用了Android Jetpack,ProcessLifecycleOwner可以监听整个应用的进程生命周期,覆盖系统杀死进程的场景:
- 先添加依赖(如果还没加):
implementation "androidx.lifecycle:lifecycle-process:2.6.2"
- 在Application中注册监听:
class MyApp : Application() { override fun onCreate() { super.onCreate() ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver { override fun onDestroy(owner: LifecycleOwner) { super.onDestroy(owner) // 进程即将销毁时存储数据 val sharedPref = getSharedPreferences("app_data", Context.MODE_PRIVATE) with(sharedPref.edit()) { putString("user_preference", "your_value") apply() } } }) } }
注意:系统内存不足杀进程时,onDestroy()可能不会触发,所以建议和onTaskRemoved()结合使用,覆盖主动关闭和被动杀死的所有场景。
最后小提醒
存储数据时一定要用apply()而不是commit()!commit()是同步写入,可能阻塞主线程;apply()是异步的,即使进程被杀,Android系统也会在后续帮你完成写入,数据不会丢失。
内容的提问来源于stack exchange,提问作者Isaac Walling
相关产品推荐
相关产品推荐

