MVP 架构,和相关的知识点。
处理子线程返回的数据Handler,
//接受子线程消息的handler,
// 静态内部类定义的Handler,避免非静态内部类的内存泄漏。
private static class MyHandler extends Handler{
//弱引用: 指向上下文对象,输入框
WeakReference<SmsCodeDialog> codeDialogRef;
public MyHandler(SmsCodeDialog context) {
this.codeDialogRef = new WeakReference<SmsCodeDialog>(context);
}
@Override
public void handleMessage(@NonNull Message msg) {
SmsCodeDialog dialog = codeDialogRef.get();
if(dialog == null) return; //activity已经被回收了.
// switch- case: IAccountManager.SMS_SEND_SUC
}
}
MVP第一步:由于网络请求和本地数据访问都在子线程中执行,返回的数据要切换到UI线程中。
可以使用上面的 mHandler.sendEmptyMessage(IAccountManager.SMS_SEND_SUC);
也可以借助RxJava 开实现线程切换。
软引用SoftReference,弱引用WeakReference 的区别。
-
【弱引用】 (Weak Reference)
实现类: java.lang.ref.WeakReference
特点: 被弱引用关联的对象只能生存到下一次垃圾收集发生之前。
机制: 当垃圾收集器开始工作,无论当前内存是否充足,都会回收掉只被弱引用关联的对象。
典型用途: 常用于实现规范化映射(Canonicalizing Mappings),例如 WeakHashMap 中的键就是一种弱引用。
它也常用于存储元数据或监听器列表,当主要对象被回收时,这些附属信息也能自动被清理,从而避免内存泄漏。 -
软引用 (Soft Reference)
实现类: java.lang.ref.SoftReference
特点: 被软引用关联的对象,在内存不足时会被回收。
机制: 垃圾收集器会在即将抛出 OutOfMemoryError 之前,回收所有只被软引用关联的对象。也就是说,只要内存足够,软引用就不会被GC回收。
典型用途: 非常适合实现内存敏感的缓存。例如,可以将图片、文件等大对象缓存到内存中。
当内存紧张时,缓存会被自动释放,避免OOM;当内存充足时,缓存又能提供快速的访问。 -
强引用 (Strong Reference)
这是最普通的引用,例如 Object obj = new Object()。
只要强引用还存在,垃圾收集器就永远不会回收掉被引用的对象。
弱引用(核心思想:使用 WeakReference,并且始终检查有效性。)
行为: 一旦垃圾收集器(GC)运行,如果这个 Context 没有被其他地方强引用,它就会被回收,WeakReference.get() 会返回 null。
优点:
及时性:能更及时地释放可能已经泄露的 Context,有助于防止内存泄漏。
确定性:它的行为是可预测的(GC即回收),让你能更明确地处理 null 的情况。
缺点: 你需要在使用前总是检查 get() 是否返回 null,因为 Context 可能在任何一次 GC 后被回收。
适用场景: 几乎所有需要包装 Context 引用的情况,尤其是:
在静态内部类或单例中持有 Context 的引用。
在异步任务(如 AsyncTask)、后台线程或 Handler 中持有 Context 的引用。
自定义 View 或 Adapter 中可能长期存在的引用。
- 软引用 (SoftReference) - 不推荐用于 Context
行为: 只有在内存不足,系统即将抛出 OOM 之前,才会回收被软引用持有的对象。
缺点:
延迟回收:这意味着一个本该被销毁的 Activity 的 Context 可能会在内存中存活非常长的时间,直到内存紧张。这实质上延长了内存泄漏的生命周期,违背了我们使用引用包装的初衷。
不可预测性:你很难预测它到底何时会被回收。
结论: 请避免使用 SoftReference 来包装 Context。它的行为特性对于解决 Context 泄漏问题是适得其反的。
原则:
1.优先使用 Application Context: 对于不涉及 UI 的操作(如获取系统服务、访问资源),永远优先使用 Context.getApplicationContext()。
Application Context 的生命周期与应用一致,不存在泄漏 Activity 的风险。
2.理解 Context 的生命周期: 不要用长生命周期的对象去引用短生命周期的对象(例如,用单例持有 Activity 的引用)。
3.现代 Android 开发中,强烈推荐使用 ViewModel 和 LiveData 来管理 UI 相关的数据。
ViewModel 的生存期比 Activity 更长(在配置变更如屏幕旋转时不会被销毁),但它不会持有对 Activity 或 View 的引用,从根本上避免了 Context 泄漏的问题。
这是 Google 官方推荐的、比手动使用 WeakReference 更优雅和强大的解决方案。
总结:
WeakReference<Context> 【推荐】 处理潜在内存泄漏的有效手段,但需时刻检查有效性。
SoftReference<Context> 【不推荐】 延迟回收,反而会延长内存泄漏,弊大于利。
使用 Application Context 【非常推荐】 从根本上避免问题,只要是和 UI 无关的操作。
使用 ViewModel + LiveData 【强烈推荐】 现代架构,官方解决方案,从设计模式上杜绝了此类问题。
最终建议:对于新项目,优先采用 ViewModel。
对于遗留代码或无法使用 ViewModel 的场景,使用 WeakReference 并做好空值检查。










网友评论