安卓后台服务布尔值重置致函数重复执行问题排查
看起来你遇到的核心问题是SharedPreferences的读写实例不统一,再加上依赖不可靠的静态变量,导致APP重启后状态丢失,重复执行通知逻辑。我来帮你拆解问题并给出修复方案:
问题根源拆解
SharedPreferences实例不匹配
你在MainActivity里用getSharedPreferences("inactivity", Context.MODE_PRIVATE)存储状态,但在后台服务和updateTrue方法里,却混用了PreferenceManager.getDefaultSharedPreferences()和getSharedPreferences("inactivity", ...)。这两个是完全不同的SP文件,相当于你把值存在了A文件,却去B文件里读,自然看不到修改后的结果。静态变量
isSeen的坑
把isSeen设为MainActivity的public static变量非常不可靠——APP重启、组件销毁重建时,静态变量会被重置,而且跨组件访问静态变量很容易出现状态不同步的问题。正确的做法是每次需要判断时,直接从SharedPreferences读取最新值。逻辑遗漏与冗余
- totalKm=200的分支没有更新状态的逻辑,会导致重复触发;
updateTrue方法里重复读取SP的操作完全没必要,修改后直接依赖下次读取即可。
修复后的代码示例
1. 统一SharedPreferences实例
所有涉及状态读写的地方,都使用同一个SP文件,不要混用默认SP:
2. 修正后台服务的milestoneCheck方法
public void milestoneCheck() { // 获取当前里程数 totalKm = (int) Float.parseFloat(TripsInfo.km.get(TripsInfo.userRank - 1)); // 统一获取SP实例 SharedPreferences sp = getSharedPreferences("inactivity", Context.MODE_PRIVATE); // 每次都从SP读取最新状态,抛弃静态变量 boolean isSeen = sp.getBoolean("inactive", false); if (totalKm == 84 && !isSeen) { milestoneNotification(totalKm); // 直接更新SP,无需额外方法 sp.edit().putBoolean("inactive", true).apply(); } else if (totalKm == 130 && isSeen) { milestoneNotification(totalKm); sp.edit().putBoolean("inactive", false).apply(); } else if (totalKm == 200 && !isSeen) { // 补充状态判断,避免重复触发 milestoneNotification(totalKm); sp.edit().putBoolean("inactive", true).apply(); } }
3. 修正AsyncTask版本的逻辑(如果用V2)
注意:通知必须在UI线程执行,AsyncTask的doInBackground是后台线程,要切换到主线程:
protected String doInBackground(String... aurl) { totalKm = (int) Float.parseFloat(TripsInfo.km.get(TripsInfo.userRank - 1)); SharedPreferences sp = getSharedPreferences("inactivity", Context.MODE_PRIVATE); boolean isSeen = sp.getBoolean("inactive", false); Log.d("test","before isSeen: " + isSeen); if (totalKm == 84 && !isSeen ) { // 切换到UI线程显示通知 runOnUiThread(() -> milestoneNotification(totalKm)); sp.edit().putBoolean("inactive", true).apply(); } else if (totalKm == 130 && isSeen) { runOnUiThread(() -> milestoneNotification(totalKm)); sp.edit().putBoolean("inactive", false).apply(); } else if (totalKm == 200 && !isSeen ) { runOnUiThread(() -> milestoneNotification(totalKm)); sp.edit().putBoolean("inactive", true).apply(); } // 验证更新后的状态 boolean updatedIsSeen = sp.getBoolean("inactive", false); Log.d("test","after isSeen: " + updatedIsSeen); return null; }
4. 移除静态变量isSeen
删掉MainActivity里的public static boolean isSeen,所有状态判断都直接从SP读取,彻底避免同步问题。
额外优化建议
- 可以给每个里程碑单独设置标记,比如用
milestone_84_seen、milestone_130_seen作为SP的key,这样不同里程碑的状态互不影响,逻辑会更清晰; - 如果你的后台服务是独立组件(比如Service),记得在获取SP时传入正确的Context,避免内存泄漏;
apply()是异步写入磁盘的,如果需要确保写入完成后再做后续操作,可以用commit()(同步),但一般apply()足够满足需求。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

