单例本身不崩溃,错误持有activity context会导致内存泄漏并引发崩溃;因activity销毁后其context失效,后续调用如getstring()、startactivity()或ui更新会抛nullpointerexception/illegalstateexception等异常。

单例模式本身不会崩溃,真正出问题的是它错误持有了 Activity 或 View 这类短生命周期对象,导致内存泄漏后在特定时机触发异常——比如 Activity 销毁后,单例仍试图调用其已失效的 Context 方法,或回调早已被回收的 UI 组件。
为什么持有 Activity Context 会引发崩溃?
Activity 的 Context 生命周期和 Activity 实例完全绑定。一旦 Activity 调用 onDestroy(),它的视图树、资源、Handler 等全部进入不可用状态。若单例中保存了该 Context(例如直接传入并赋值给静态字段),后续任何对它的调用——比如 context.getString(R.string.xxx)、context.startActivity(),甚至只是访问 context.getResources()——都可能抛出 NullPointerException 或 IllegalStateException。
更隐蔽的情况是:单例内部启动了异步任务(如 Retrofit 回调、Handler.post、RxJava 订阅),而任务完成时 Activity 已销毁。此时回调中若直接更新 UI 或使用 Activity Context,就会 crash。
典型崩溃场景还原
-
网络请求回调更新 UI:单例管理网络层,传入了 Activity 的 Context 用于显示 Toast;请求返回时 Activity 已 finish,
toast.show()抛出WindowManager$BadTokenException -
静态 Handler 持有 Activity 引用:非静态内部类 Handler 默认持有外部 Activity 引用;Activity 销毁后 Handler 中仍有延时消息,执行时调用
activity.findViewById()→NullPointerException - 监听器未解注册:单例注册了 Activity 的 LifecycleObserver 或广播接收器,但没在 onDestroy() 中移除;后续回调触发时 Activity 实例为空
怎么避免?核心就两条
第一,Context 一律用 getApplicationContext():只要不涉及 UI 操作(如弹窗、启动 Activity、inflate 布局),所有单例、工具类、数据层组件都应只持有 Application Context。它生命周期与进程一致,安全可靠。
第二,短生命周期对象绝不存为静态/单例成员:Activity、Fragment、View、Adapter、Listener 这些对象,禁止以强引用形式保存在单例里。必须关联时,用 WeakReference 包一层,并在使用前判空:
private WeakReference<activity> mActivityRef;</activity>mActivityRef = new WeakReference(currentActivity);Activity activity = mActivityRef.get();if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) { // 安全使用}
额外注意:构造函数异常也会让单例“失效”
如果单例的静态初始化块或私有构造函数抛出异常(比如读取配置失败、初始化数据库出错),JVM 会将该类标记为“初始化失败”。之后任何线程尝试获取实例,都会直接抛 NoClassDefFoundError——这看起来像单例“突然没了”,其实是类加载机制的保护行为。务必确保构造逻辑健壮,或捕获异常做兜底。











