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

Android SharedPreferences空指针异常求助:偶发崩溃如何修复?

偶发NullPointerException的原因分析与解决思路

看起来你遇到的是Fragment中常见的Context为空导致的偶发崩溃问题,我来帮你拆解下原因和可行的解决办法:

问题根源

从错误栈可以看出,NPE出现在PrefManager的构造函数里调用_context.getSharedPreferences()时,而_context是从PlayerFragment的getActivity()传过来的。偶发的核心原因是:

当Fragment已经和宿主Activity解除关联时(比如Fragment被destroy、detach,或者Activity正在销毁过程中),getActivity()会返回null。

具体到你的场景:ExoPlayer的onPlayerStateChanged是异步回调,这个回调可能在Fragment已经不在前台、甚至已经和Activity分离的时候触发(比如用户快速切换Fragment、切到后台),此时调用addView(),里面的new PrefManager(getActivity())就会传入null,最终导致调用getSharedPreferences时抛出NPE。

解决思路

1. 在使用getActivity()前先判空

在PlayerFragment的addView()方法里,先检查Context是否有效,避免传入null到PrefManager:

public void addView() {
    Context context = getActivity();
    if (context == null) {
        // 可以记录日志,或者直接返回避免后续崩溃
        Log.w("PlayerFragment", "Context is null, skipping addView logic");
        return;
    }
    final PrefManager prefManager = new PrefManager(context);
    Integer id_user = 0;
    String key_user= "";
    // 注意:这里用常量equals变量,避免getString返回null时触发NPE
    String loggedStatus = prefManager.getString("LOGGED");
    if ("TRUE".equals(loggedStatus)) {
        id_user= Integer.parseInt(prefManager.getString("ID_USER"));
        key_user= prefManager.getString("TOKEN_USER");
    }
    // 后续逻辑...
}

2. 给PrefManager添加空值校验

在PrefManager的构造函数里提前检查传入的Context是否为空,要么抛出明确的异常方便排查,要么做降级处理:

public PrefManager(Context context) {
    if (context == null) {
        throw new IllegalArgumentException("Context cannot be null when initializing PrefManager!");
        // 或者如果需要降级,使用Application Context(前提是你有自定义Application)
        // this._context = MyApp.getInstance().getApplicationContext();
    }
    this._context = context;
    pref = _context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
    editor = pref.edit();
    editor.apply();
}

3. 绑定ExoPlayer回调与Fragment生命周期

因为ExoPlayer的回调可能在Fragment生命周期之外执行,所以要在Fragment销毁时移除监听或释放Player资源,避免无效回调:

@Override
public void onDestroy() {
    super.onDestroy();
    if (exoPlayer != null) {
        // 移除你设置的Player状态监听
        exoPlayer.removeListener(this);
        exoPlayer.release();
        exoPlayer = null;
    }
}

4. 使用Application Context代替Activity Context

如果你的SharedPreferences是全局使用的,不需要依赖Activity生命周期,可以改用Application Context,它是全局唯一且不会被回收的:

// 在PlayerFragment里获取Application Context
final PrefManager prefManager = new PrefManager(requireContext().getApplicationContext());

或者在PrefManager内部自动切换到Application Context:

public PrefManager(Context context) {
    // 确保使用Application Context,避免Activity销毁导致的空指针
    this._context = context.getApplicationContext();
    pref = _context.getSharedPreferences(PREF_NAME, PRIVATE_MODE);
    editor = pref.edit();
    editor.apply();
}

总结

这个偶发崩溃的核心是异步回调时机与Fragment生命周期不同步,导致Context失效。解决的关键是确保使用Context前做非空校验,或者使用更稳定的Application Context,同时管理好ExoPlayer的生命周期绑定,避免无效回调触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:58:21