android中非静态内部类易导致内存泄漏,应改用静态内部类+weakreference,并在销毁时清理消息和资源,避免直接引用宿主或使用匿名内部类。

Android 中非静态内部类(比如 Handler、Runnable、AsyncTask 子类)会隐式持有外部 Activity 或 Fragment 的强引用,一旦内部类生命周期长于宿主(例如异步任务未完成、Handler 消息未处理完),宿主就无法被 GC 回收,造成内存泄漏。核心思路是:切断内部类对宿主的强引用链。
用静态内部类 + WeakReference 替代非静态内部类
这是最常用也最稳妥的方式。静态内部类不持有外部类引用,再通过 WeakReference 安全访问宿主对象:
- 将内部类声明为 static,消除编译器自动注入的
this$0引用 - 在静态内部类中持有一个
WeakReference<activity></activity>或WeakReference<fragment></fragment> - 每次使用前调用
get()并判空,避免空指针 - 示例:Handler、TimerTask、回调监听器等都适用此模式
及时清理内部类持有的资源和消息
即使用了弱引用,仍需主动清理残留任务,防止弱引用虽为空但消息/任务还在排队:
- 在 Activity 的
onDestroy()或 Fragment 的onDestroyView()中,调用handler.removeCallbacksAndMessages(null) - 取消 AsyncTask(已废弃,但仍见于旧项目):检查
getStatus() == Status.RUNNING后调用cancel(true) - 停止 Timer、清空 Runnable 队列、注销 RxJava 的
CompositeDisposable.clear()
避免在内部类中直接使用 this 或匿名内部类引用宿主
常见高危写法要立刻改掉:
- 不要写
new Handler() { ... }—— 这是典型的非静态匿名内部类 - 不要在内部类里直接调用
findViewById()、setText()等 UI 方法,除非已确认宿主还存活 - 不要把 Activity 实例作为参数传进内部类构造函数并赋给普通字段(应改为 WeakReference)
- 避免在内部类中注册广播接收器、监听器后忘记反注册
优先考虑外部独立类或接口回调代替内部类
不是所有场景都必须用内部类。更清晰、更易测试、更少泄漏风险的做法包括:
- 把耗时逻辑抽成独立的 Worker 类(如继承
Worker或使用CoroutineScope),通过接口回调通知 UI - 使用 Lifecycle-aware 组件(如
ViewModel+LiveData或StateFlow),天然规避生命周期问题 - 用
viewLifecycleOwner替代lifecycleOwner处理 Fragment 中的协程或 LiveData 观察
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











