拓冰建站拓冰建站
首页 / 资讯中心 / 正文

MicroReader如何避免内存泄漏?MVP中Presenter生命周期管理的5个要点

MicroReader如何避免内存泄漏MVP中Presenter生命周期管理的5个要点【免费下载链接】MicroReader一个小而美的阅读客户端项目地址: https://gitcode.com/gh_mirrors/mi/MicroReaderMicroReader 是一个开源的小而美 Android 阅读客户端聚合了知乎日报、果壳、微信精选、IT之家和微博视频等内容。很多开发者学习这个项目时最常问的问题就是MVP 架构下如何避免内存泄漏内存泄漏的根源往往不在 View 层而在Presenter 的生命周期管理上——请求还没回来页面却已经关闭了。本文结合 MicroReader 的真实源码拆解 MVP 中 Presenter 生命周期管理的 5 个要点帮你彻底告别 OOM 和回调崩溃。MVP 为什么容易内存泄漏先看懂这条引用链MVP 的核心是 Presenter 持有 View 接口、发起网络请求、再回调刷新 UI。看似简洁隐患却藏在细节里Activity/Fragment 销毁后Presenter 还活着它的回调方法仍会尝试访问已销毁的 View引发崩溃或泄漏RxJava 订阅未取消IO 线程任务完成后仍持有外层引用形成无法回收的对象链Context 被长期持有Activity 无法被 GC 回收一次泄漏就是几 MB 起步。MicroReader 的代码规模不大却把 MVP 生命周期管理的套路做得相当完整非常适合作为学习范本。下面逐一拆解它的 5 个关键做法。要点 1用 CompositeSubscription 统一管理 RxJava 订阅MicroReader 基于 RxJava 1.x 发起网络请求而 RxJava 是内存泄漏的重灾区——订阅一旦建立回调闭包就会持有外部对象。它的解法是抽出基类BasePresenterImpl用CompositeSubscription把所有订阅装进一个容器在app/src/main/java/name/caiyao/microreader/presenter/impl/BasePresenterImpl.java中addSubscription(Subscription s)每个请求生成的 Subscription 都丢进 CompositeSubscriptionunsubcrible()一次性取消所有订阅。所有业务 Presenter如ZhihuPresenterImpl、GuokrPresenterImpl、VideoPresenterImpl、MainPresenterImpl都继承这个基类并在每次请求后调用addSubscription(subscription)。这样统一收口的好处是取消订阅只需一行代码谁也不会漏掉。小提示用 RxJava 2.x 时对应的是CompositeDisposable思路完全一致。要点 2解绑时机要对齐生命周期onDestroyView 是最佳窗口有了容器还得在正确的时机清空它。MicroReader 的做法是在 Fragment 的onDestroyView中解绑例如app/src/main/java/name/caiyao/microreader/ui/fragment/ZhihuFragment.javaOverride public void onDestroyView() { super.onDestroyView(); mUnbinder.unbind(); mZhihuPresenter.unsubcrible(); }为什么选onDestroyView而不是onDestroy因为页面不可见时回调就不再需要——比如切到后台、滑出屏幕此时立即取消订阅既能避免泄漏又能节省流量和 CPU。unsubcrible()内部调用CompositeSubscription.unsubscribe()会把所有网络回调一并掐断即使请求晚到也无法再触碰已经销毁的 View。要点 3Presenter 持有 View 要轻——面向接口 构造校验很多内存泄漏是强引用导致的Presenter 直接持有 Activity 实例Activity 想回收却被拽住不放。MicroReader 的规避手法有两个第一面向接口持有。ZhihuPresenterImpl里保存的是IZhihuFragment接口而不是具体的 Fragment 实现。接口只暴露showProgressDialog()、updateList()等必要方法Presenter 和 View 解耦替换、测试都更方便。第二构造时强制校验。每个 Presenter 的构造函数都检查 View 是否为空为空直接抛异常if (iZhihuFragment null) throw new IllegalArgumentException(iZhihuFragment must not be null);这保证 Presenter 一出生就绑定一个有效 View避免后续空指针和悬空引用。要点 4Context 要短命绝不长期攥着 ActivityPresenter 里需要 Context 时很多新手会顺手把 Activity 存成成员变量——这是最经典的泄漏姿势。MicroReader 的 Presenter 是这样处理 Context 的它把 Context 传给CacheUtil用于构建磁盘缓存而CacheUtil内部只取ctx.getCacheDir()得到缓存目录路径并没有把 Activity 引用保存下来见app/src/main/java/name/caiyao/microreader/utils/CacheUtil.java。实践建议能用getApplicationContext()就不用 Activity工具类、单例里不要存 Activity 字段确需传 Context 时用完即弃别让它活过当前页面。要点 5内存不够缓存来凑——磁盘缓存优先避免内存泄漏的另一半是降低内存占用。MicroReader 的列表数据知乎日报、果壳、视频并没有全部堆在内存里而是通过CacheUtil落盘缓存默认缓存目录getCacheDir()大小上限 50MB超额自动按最久未使用LRU 思路清除数据先读缓存再发请求CacheUtil.getAsJSONObject(Config.ZHIHU)这类方法让秒开成为可能列表使用RecyclerView 复用机制图片交给ImageLoader异步加载避免一次性持有大量 Bitmap。内存里只保留当前屏幕需要的数据其余交给磁盘——页面销毁后缓存对象不占用任何堆内存泄漏自然无从谈起。总结一张清单检查你的 MVP 内存安全把这 5 个要点浓缩成一张自查清单照着检查你的项目检查项正确做法对应源码订阅管理CompositeSubscription 统一收口presenter/impl/BasePresenterImpl.java解绑时机onDestroyView 中 unsubcribleui/fragment/ZhihuFragment.javaView 持有面向接口 构造校验非空presenter/impl/ZhihuPresenterImpl.javaContext不存 Activity用后即弃utils/CacheUtil.java缓存策略磁盘缓存优先限制大小utils/CacheUtil.javaMVP 的内存泄漏从来不是玄学它只是生命周期没有对齐的必然结果。MicroReader 用 5 个朴素而扎实的手法把小而美的阅读体验建立在稳定的内存管理之上——这份思路值得每个 Android 开发者抄进自己的项目里。想亲手跑一遍源码、对照学习的话可以git clone https://gitcode.com/gh_mirrors/mi/MicroReader在本地断点调试效果更直观。【免费下载链接】MicroReader一个小而美的阅读客户端项目地址: https://gitcode.com/gh_mirrors/mi/MicroReader创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门