今天上午面试一个有4年android工作经验的人, 他最近的项目中用到了MVP模式。 我问他MVP模式应该注意什么? 他并不清楚。。。 百度查了一下, 好像也没这方面的博客, 所以我想写一下。
如果不懂MVP模式, 请先百度一下。
其实MVP模式有2个潜在的问题:
1、 Activity/Fragment持有Presenter的引用, Presenter里保存了Activity/Fragment实现的回调接口类引用, 即出现相互引用的情况, gc无法回收activity/fragment和presenter, 出现内存泄漏。经网友指正:Android dalvik使用mark-sweep即标记回收法, 如果没有其它引用指向这2个对象也会被回收。 但从代码规范角度来说最好在退出函数里赋空值解开闭环; 建议Presenter使用弱引用指向Activity/Fragment, 在http/https返回数据时判断弱引用是否为空和isFinishing等。
上图是标记删除法, 从根节点访问不到的对象都会被回收。
解决方法: 避免相互强引用, View层持有Presenter的强引用, Presenter持有View的弱引用。 在Presenter类里声明一个方法, 重置接口引用为空; 在Activity/Fragment的onStop或onDestroy里调用Presenter的重置方法。
2、 打开Activity/Fragment时, 会在onCreate或onCreateView方法里调用若干个网络接口拉数据, 这些接口是放到线程里异步执行的, 假如快速打开并关闭Activity/Fragment该怎么办? 这时还有很多网络接口正在执行或在队列里的请求, 不光费流量, 在回调里刷界面还会崩溃!
解决方法:在Activity/Fragment的onDestroy函数里取消所有该界面发出的网络接口, 我用的是OkHttp3.4.1版本。 每个Request都可以用tag区分, 在取消请求时通过这个tag找到对应的实例。
Request request = new Request.Builder() .url(url) .tag("tagGetNewsDetail")OkHttp删除请求的方式:
List<Call> calls = sInstance.dispatcher().queuedCalls(); if (calls != null && calls.size()>0) { for (int i=0; i<calls.size(); i++) { Call call = calls.get(i); if (Util.equal(tag, call.request().tag())) { call.cancel(); } } }
一个app的所有界面都可以按照MVP模式写代码, 按照模型方法模式的思想,