Android非Activity类调用SharedPreferences工具类后台清理后崩溃
问题分析与解决方案
这个问题我太熟悉了!核心原因是你依赖了MainActivity的静态SharedPreferences实例——当APP从最近应用列表被移除后,系统大概率会杀掉你的App进程。之后BroadcastReceiver触发时,App进程会被重新拉起,但此时MainActivity并不会被初始化(因为不是通过启动Activity的方式唤起的),那个静态的SP实例自然就是null,调用它的方法肯定会崩溃。
下面给你两个靠谱的解决方案,按推荐程度排序:
方案1:用Application上下文获取SharedPreferences(最推荐)
Application的生命周期和整个App进程完全绑定,不会因为某个Activity销毁而失效,用它的上下文获取SP是最安全的做法。
步骤1:创建自定义Application类
public class MyApp extends Application { private static Context appContext; @Override public void onCreate() { super.onCreate(); appContext = getApplicationContext(); } public static Context getAppContext() { return appContext; } }
步骤2:在Manifest中注册自定义Application
<application android:name=".MyApp" <!-- 其他原有属性保持不变 --> ...> <!-- 你的Activity、Receiver等注册信息 --> </application>
步骤3:修改LocationRequestHelper类
彻底脱离对MainActivity的依赖,改用Application上下文获取SP:
public class LocationRequestHelper { private static final String PREF_NAME = "AppPrefs"; private static final String KEY_USER_ID = "user_id"; // 封装SP获取逻辑,内部用Application上下文 private static SharedPreferences getSharedPreferences() { return MyApp.getAppContext().getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); } public static void setUserId(String userId) { getSharedPreferences().edit().putString(KEY_USER_ID, userId).apply(); } public static String getUserId() { // 返回空字符串而非null,避免后续API调用出现空指针 return getSharedPreferences().getString(KEY_USER_ID, ""); } }
这样不管是MainActivity调用setUserId,还是BroadcastReceiver触发Utils调用getUserId,都能稳定获取SP实例,就算进程被重新拉起,只要Application初始化完成(进程启动就会触发),SP就能正常工作。
方案2:直接传递Context到Helper方法(轻量替代)
如果不想自定义Application,也可以直接在调用Helper方法时传入有效的Context:
修改LocationRequestHelper类
public class LocationRequestHelper { private static final String PREF_NAME = "AppPrefs"; private static final String KEY_USER_ID = "user_id"; public static void setUserId(Context context, String userId) { context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) .edit().putString(KEY_USER_ID, userId).apply(); } public static String getUserId(Context context) { return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) .getString(KEY_USER_ID, ""); } }
调用示例
- 在MainActivity中:
LocationRequestHelper.setUserId(this, "1") - 在BroadcastReceiver的
onReceive方法中:LocationRequestHelper.getUserId(context)
这种方式也能避免依赖静态的Activity实例,只要传入的Context是有效的(比如Application上下文或者Receiver的上下文),就不会出现崩溃问题。
再帮你捋清崩溃的逻辑链
- APP在后台时,进程还存活,MainActivity的静态SP实例依然有效,调用正常;
- 从最近列表移除APP后,系统为释放内存杀掉App进程;
- 后续BroadcastReceiver触发时,系统仅拉起App进程并初始化Application和Receiver,不会启动MainActivity;
- 此时你在MainActivity中初始化的静态SP实例根本没被创建,是null,调用
getUserId()时直接抛出NullPointerException导致崩溃。
内容的提问来源于stack exchange,提问作者Code Spy
相关产品推荐
相关产品推荐

