博主声明:

转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。

本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/smile_running

MVP 架构系列文章:

Android MVP 架构(一)MVP 架构介绍与实战运用

Android MVP 架构(二)MVP 之 BaseMVP 基础框架设计

Android MVP 架构(三)MVP 内存泄漏分析与动态代理

Android MVP 架构(四)MVP 泛型 Model 的配置

Android MVP 架构(五)MVP 多个 Presenter 依赖注入

Android MVP 架构(六)MVP 之 BaseFragment 的封装

Android MVP 架构(七)MVP 之代理模式消除重复代码(结束)

源码地址:

github下载:MVPDemo

csdn 下载:MVPDemo

上篇文章(Android MVP 架构(二)MVP 之 BaseMVP 基础框架设计),我们讲到了如何封装一个 BaseMVP 基类,使用这个模板,可以避免我们写很多重复性的代码以及一些必要的处理,避免发生漏写的错误,还有同样的代码写多了也肯定很烦。不过,从上篇的文章的 BaseMVP 封装来看,还是有一些不足之处,比如会不会造成内存泄漏的问题?比如每次调用 View 层的方法时,都要去判断 View 层是不是被摧毁了,是不是为 NULL 的情况。鉴于这两个问题,我们这次就针对这两个问题进行分析和解决。

  • 内存泄漏

第一个问题:会不会造成内存泄漏的问题?

这个问题涉及到内存泄漏的问题,那就先看看内存泄漏是什么吧!在 Java 中的 GC(垃圾回收器)就是来回收那些已经没用了的对象,已经被释放掉对象的内存,因为正是 Java 的这种垃圾回收机制,所以我们才不需要手动去释放对象引用的内存。相信大家在大学中都有学过 C、C++ 语言,肯定会在指针那里有所顾忌。我们每一次都需要通过在内存地址中开辟一段内存来存放指针的引用对象,而当指针对象使用完了后,必须手动给它置空的操作。而在 Java 中却的 GC 已经帮我们做了这样的工作,但是呢, GC 其实也不是那么万能的,它是通过一些算法来控制对象引用的回收,那么我们就应该去了解 GC 的回收算法及原理。

说了这么多,你应该大致有个了解,内存泄漏就是当 GC 来回收时,然而这些对象没有得到释放,或者被其它的给引用了,这种情况下 GC 是不会自动回收的,而这块内存就会被一直占用着,得不到释放,这就是内存泄漏的基本概念。然而,程序这样的情况越来越多时,程序就会出现卡顿、奔溃、报异常的现象,当这些对象占用的内存达到一定的临界值时,机器中没有多余可用的内存,这时你再去申请内存空间,就会发生 OOM (内存溢出)。所以说,内存泄漏是一种安全隐患,它直接影响的是程序的性能。要想在这方面做的好,这需要一个深入的研究。

多的也不扯淡了,我们继续来看问题。BaseMVP 其实也是会造成内存泄漏的一大安全隐患,它的内存泄漏是来自于 View 层与 Presenter 层之间的强引用关系。我们在 Presenter 层直接绑定了 View 才可以拿到 View 层的引用,它们之间是强引用的关系,如果不进行解绑的话,那就会造成内存泄漏的情况发生。为什么不解绑就会内存泄漏呢?我们来看看代码:

public abstract class BasePresenter<V extends IBaseView> implements IBasePresenter {protected V mView;@SuppressWarnings("unchecked")@Overridepublic void attech(IBaseView view) {mView = (V) view;}@Overridepublic void detech() {
//        mView = null;}
}

这里,我们不解绑 View,也就是 mView = null 注释掉,意味着 Presenter 层还持有 View 的引用,当 Activity 被关闭时,Activity 相当于 View 层,由于 Activity 还是被 Presenter 层引用了,当 GC 来了,它一看 Activity 被引用了,所以就不会去回收它。当你再次打开 Activity 又关闭时,Activity 又申请了一段新的内存空间,GC 又没去回收它,久而久之,势必会内存溢出。

而这里置空了就不会造成内存泄漏,因为此时的 View,也就是 Activity 的引用被释放了,如果再也没有其他类引用到 Activity 对象的时候,当 GC 来时,发现 Activity 是可以回收的,就把它回收掉了,这段内存空间就释放了。

说了这么多,其实就是为了介绍我们自己写的 BaseMVP 存在的内存泄漏问题,这里的代码还是基于上一篇 MVP v2 版本进行修改,因为 V 与 P 之间是强引用,所以我们就改为软引用的方式,避免内存泄漏导致的 OOM 情况发生。代码我做了一点细微的修改,代码如下:

BasePresenter 基类修改:

package com.test.mvp.mvpdemo.mvp.v3.basemvp;import java.lang.ref.SoftReference;public abstract class BasePresenter<V extends IBaseView> implements IBasePresenter {private SoftReference<IBaseView> mReferenceView;@SuppressWarnings("unchecked")@Overridepublic void attech(IBaseView view) {mReferenceView = new SoftReference<>(view);}@SuppressWarnings("unchecked")public V getView() {return (V) mReferenceView.get();}@Overridepublic void detech() {mReferenceView.clear();mReferenceView = null;}
}

使用软引用的方式让 P 层持有 V 层的引用,并且提供了 getView() 方法给 P 层调用,父类 View 变量进行私有化,防止子类对其进行更改造成的其他错误。我们的 MainPresenter 获取 Activity 的引用就可以使用 getView() 方法获得。软引用在内存降到不足的情况下,GC 就会进行优先回收释放那些以软引用方式引用的对象,一定程度上去避免内存溢出(OOM)。

  • 动态代理

第二个问题:每次都要让 View 做空判断,很烦?

/*** presenter 层,承担业务逻辑处理,数据源处理等*/
public class MainPresenter extends BasePresenter<MainContract.IMainView> implements MainContract.IMainPresenter {private MainContract.IMainModel mModel;@Overridepublic void attech(IBaseView view) {super.attech(view);mModel = new DataModel();}@Overridepublic void handlerData() {if (getView() != null) {getView().showDialog();}mModel.requestBaidu(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, Response response) throws IOException {String content = response.body().string();if (getView() != null) {getView().succes(content);}}});}@Overridepublic void detech() {super.detech();/*** 释放内存、关闭网络请求、关闭线程等操作*/Log.d("==========", "detech: 解除绑定,释放内存");}
}

为什么要用动态代理呢?我们看上面的 getView()代码,没次都需要判断 null 类型,是不是非常麻烦,又因为这里的 View 类型是一个接口(V extends IBaseView)泛型接口,所以这就好办了,动态代理完全就可以做到统一的空类型判断,那么这里的代码修改为如下:

package com.test.mvp.mvpdemo.mvp.v3.basemvp;import java.lang.ref.SoftReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public abstract class BasePresenter<V extends IBaseView> implements IBasePresenter {private SoftReference<IBaseView> mReferenceView;private V mProxyView;@SuppressWarnings("unchecked")@Overridepublic void attech(IBaseView view) {mReferenceView = new SoftReference<>(view);mProxyView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object o, Method method, Object[] objects) throws Throwable {if (mReferenceView == null || mReferenceView.get() == null) {return null;}return method.invoke(mReferenceView.get(), objects);}});}@SuppressWarnings("unchecked")public V getView() {return mProxyView;}@Overridepublic void detech() {mReferenceView.clear();mReferenceView = null;}
}

使用动态代理之后,我们在 Presenter 的实现类中就不需要做 View 层的空类型判断了,这样既节省了代码,虽然没有多少代码,但是写起来还是很烦的,又让我们的代码变得更加优雅。

那么,这篇文章就结束了,通过这篇文章为 BaseMVP 继续加料,我们的 BaseMVP 基础框架也有模有样了,要想做的更好,还需要继续去优化代码。不着急,我们一次一次慢慢的搞定它。

Android MVP(三)内存泄漏分析与动态代理相关推荐

  1. Android常见的内存泄漏分析

    内存泄漏原因 当应用不需要在使用某个对象时候,忘记释放为其分配的内存,导致该对象仍然保持被引用状态(当对象拥有强引用,GC无法回收),从而导致内存泄漏. 常见的内存泄漏源头 泄漏的源头有很多,有开源的 ...

  2. android MVP 模式内存泄漏如何解决

    MVP简介 M-Modle,数据,逻辑操作层,数据获取,数据持久化保存.比如网络操作,数据库操作 V-View,界面展示层,Android中的具体体现为Activity,Fragment P-Pres ...

  3. android释放acitity内存,Android 内存泄漏分析与解决方法

    在分析Android内存泄漏之前,先了解一下JAVA的一些知识 1. JAVA中的对象的创建 使用new指令生成对象时,堆内存将会为此开辟一份空间存放该对象 垃圾回收器回收非存活的对象,并释放对应的内 ...

  4. Android内存泄漏分析及调试

    2019独角兽企业重金招聘Python工程师标准>>> Android内存泄漏分析及调试 分类: Android2013-10-25 11:31 5290人阅读 评论(5) 收藏 举 ...

  5. Android 内存泄漏分析指北

    android 内存泄漏分析指北 简单来说内存泄漏就是当对象不再被应用程序使用,但是垃圾回收器却不能移除它们,因为它们正在被引用 java 垃圾回收介绍: Java 虚拟机运行所管理的内存包括以下几个 ...

  6. Android内存泄漏分析

    内存泄漏指的是程序中不再使用的对象对象由于某些原因无法被正常GC回收.对象没 有及时释放,就会占据宝贵的内存空间,因而导致后续分配内存的时候,内存空间不足出现OOM.如果无用对象占据的控件越大,那么可 ...

  7. Android 内存泄漏分析与解决方法

    Android 内存泄漏分析与解决方法 参考文章: (1)Android 内存泄漏分析与解决方法 (2)https://www.cnblogs.com/start1225/p/6903419.html ...

  8. android分析内存工具,Android Studio内存泄漏分析工具汇总

    Android Studio内存泄漏分析工具汇总 时间:2017-04-25     来源:Android开发学习网 在Android开发过程中,让人头疼的就是内存泄露问题了,很小的一个错误都会引起内 ...

  9. Mac Android 内存泄漏分析 实战演练

    虚的概念就不讲了,自己去网上搜,一大堆.  这里来一次真刀真枪的实操实战演练. 简书上有一篇讲解 内存泄漏分析 的文章,总结的很到位,由浅入深,比较全面.建议结合起来阅读 内存泄露实例分析 -- An ...

最新文章

  1. 使用Active Directory的常见问题2
  2. Class Activation Mapping (CNN可视化) Python示例
  3. 找到100亿个URL中重复的URL及搜索词汇的TopK问题
  4. java简单工厂模式_Java 简单工厂模式
  5. 实例演示在SQL中启用全文检索
  6. 如何验证python的下载安装_如何下载python并正确安装
  7. js setTimeout 使用方法
  8. leetcode 42 python
  9. Professional ASP.NET 2.0之跨页提交-Cross Page Posting
  10. 超给力,一键生成数据库文档-数据库表结构逆向工程
  11. Python实战:利用Uplift模型识别营销敏感用户提升转化率(一)
  12. Module not found: Error: [CaseSensitivePathsPlugin]
  13. Django实战教程
  14. 编译原理——自上而下语法分析
  15. sublime插件 —— 一键美化HTML/CSS/JS代码
  16. ssm体育用品库存管理毕业设计-附源码211712
  17. 马云:30年后每对年轻人要养8个老人 管理5套房子
  18. web开发下的HTTP编程及接口回调的使用
  19. 金融行业容器平台落地路径:敏捷响应业务更迭 1
  20. 专题:解析WINDOWS命令行下的的磁盘清理程序CLEANMGR

热门文章

  1. 我和Python的Py交易》》》》》》数据类型
  2. ​docker容器加速
  3. puppet三种认证注册方式详解及常见报错分析
  4. unity实现神笔马良效果
  5. Nginx实战学习之负载均衡
  6. 王者战力查询,安卓苹果都行
  7. 学习笔记-会话技术CookieSession
  8. 使用FLuke福禄克MicroScanner2 POE(MS-POE)检测以太网供电
  9. 开价20w美元,这家公司想买下你的脸!不限性别年龄,预计2023年投入机器人使用...
  10. Ubuntu 16.04安装Zimbra邮件服务器