Android MVP Presenter 中引发的空指针异常
一、概述
最近对 googlesamples/android-architecture 中的 MVP-dagger 进行了学习。对照项目的 MVP-dagger 分支,对 MVP-dagger 进行了实践,不日将会在另一篇文章中进行介绍。
MVP 架构,顾名思义,Model-View-Presenter。其作用是解决 Android 的 MVC 架构中,Activity 的职责不清,过于庞杂,难以维护的缺点。
在众多对 MVP 的实践中,Presenter 常有 attachView 和 unattachView 两个方法,用以建立起 Presenter 同 View 的联系,便于在 Presenter 中对 View 的接口进行调用。
然而,Presenter 中常常有一些耗时的操作,在某些情况下(诸如用户退出对应的 View),unAttachView 被调用,此时 Presenter 才完成耗时操作,需要完成对 View 的更新。但此时由于 View 已经被解绑,Presenter 中获取到的 View 为空,若不进行判空操作,则会引起空指针异常。
在 Presenter 中如何优雅地判空?通过进一步了解 Presenter 的生命周期,能不能找到更好的解决方案?这两个问题是本文要讨论的重点!
二、Presenter 中对 View 判空
2.1 最简单直接的暴力方式
public class TopicDetailPresenter extends RxPresenter<TopicDetailContract.View> implements TopicDetailContract.Presenter {
private RetrofitHelper mRetrofitHelper;
@Inject
TopicDetailPresenter(RetrofitHelper retrofitHelper) {
this.mRetrofitHelper = retrofitHelper;
}
@Override
public void getTopicDetailData(int topicId) {
mRetrofitHelper.fetchTopicNewsList(topicId).enqueue(new Callback<TopicStoryListBean>() {
@Override
public void onResponse(Call<TopicStoryListBean> call, Response<TopicStoryListBean> response) {
if (response.isSuccessful()) {
mView.showContent(response.body());
}
}
@Override
public void onFailure(Call<TopicStoryListBean> call, Throwable t) {
mView.showError(t.getMessage());
}
});
}
}
在上面这个例子中,并没有对 mView 进行判空,当网络状态不好,用户退出当前 Presenter 关联的 View,就极容易引起空指针异常。
为了避免此问题的出现,应当对 mView 进行判空操作。
if(mView != null) mView.showContent(response.body());
...
if(mView != null) mView.showError(t.getMessage());
这是最直接了当的做法。倘若对整个项目进行如是改造,且不说编码规范和设计原则的问题,单是修改整个项目的 Presenter 就得费老鼻子劲儿,修改过程也极容易出现遗漏等问题。
暴力××不可取呀!!!
2.2 整合抽象的方式
当然了,上面的代码在代码规范和设计模式上也有一定的问题。一种更佳的方式是,不直接让子 Presenter 对 mView 进行操作,而是使用 getView 方法对 mView 进行暴露,用户使用 getView 获取绑定的 view
if(getView() != null) getView().showContent(response.body());
...
if(getView() != null) getView().showError(t.getMessage());
2.3 优雅的判空方式
来自知乎专栏的一片文章 『极光日报 - 不要再在你的 Presenter 中检查 view != null 啦』 中介绍了一种优雅的方式,抛异常/使用第三方库。
有另一种我认为更好的方式,就是将 2.2 与 抛异常结合起来。毕竟,谁都不想为了一些小的细节,而引入一个第三方库。
public class TopicDetailPresenter extends RxPresenter<TopicDetailContract.View> implements TopicDetailContract.Presenter {
private RetrofitHelper mRetrofitHelper;
@Inject
TopicDetailPresenter(RetrofitHelper retrofitHelper) {
this.mRetrofitHelper = retrofitHelper;
}
@Override
public void getTopicDetailData(int topicId) {
mRetrofitHelper.fetchTopicNewsList(topicId).enqueue(new Callback<TopicStoryListBean>() {
@Override
public void onResponse(Call<TopicStoryListBean> call, Response<TopicStoryListBean> response) {
if (response.isSuccessful()) {
getView().showContent(response.body());
}
}
@Override
public void onFailure(Call<TopicStoryListBean> call, Throwable t) {
getView().showError(t.getMessage());
}
});
}
}
在父 Presenter 中
protected View getView(){
if(mView == null) throw new IllegaStateException("view not attached");
else return mView;
}
三、Presenter 的生命周期
这个话题源自一篇文章 『Android:聊聊 MVP 中 Presenter 的生命周期』
当然,这篇文章涵盖了处理 Presenter 的生命周期 与 Activity/Fragment 生命周期同步的问题的几个框架。同步 Presenter 和 Activity/Fragment 生命周期,从而保证在 View 层(这里姑且 Activity/Fragment 归类到 View 层吧)生命结束后,Presenter 也被终止生命,故而避免了空指针异常的问题!
这里只引用文中的几个框架,详细分析内容,可参见原文!
Beam 框架
『不要再给MVP中Presenter写接口了』观点不敢苟同Loader 框架
原文中详细介绍了这种方案
此文在我的 Github Pages 上同步发布,地址为:Android MVP Presenter 中引发的空指针异常
Android MVP Presenter 中引发的空指针异常的更多相关文章
- Android MVP 架构一 View与Presenter
View:主要负责界面的显示及跟数据无关的逻辑,比如设置控件的点击事件等 Presenter:主要负责View与Model的交互 Model:数据部分 ------- MVP的核心是: View层不持 ...
- [Android]Android MVP&依赖注入&单元测试
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5422443.html Android MVP&依赖注入 ...
- Android MVP+Retrofit+RxJava实践小结
关于MVP.Retrofit.RxJava,之前已经分别做了分享,如果您还没有阅读过,可以猛戳: 1.Android MVP 实例 2.Android Retrofit 2.0使用 3.RxJava ...
- Android MVP模式 谷歌官方代码解读
Google官方MVP Sample代码解读 关于Android程序的构架, 当前(2016.10)最流行的模式即为MVP模式, Google官方提供了Sample代码来展示这种模式的用法. Repo ...
- Android MVP + 泛型,实现了友好VP交互及Activity潜在的内存泄露的优化
Android MVP粗来已经有段时间了,在项目中我也多多少少用了一些,不得不说代码使用这种模式后,条例确实清晰了好多,整个流程看起来有点各司其职的感觉(另一种的java面向对象的方式). 不过这里是 ...
- Android MVP理解
Android默认采用的是MVC: View:对应于布局文件 Model:业务逻辑和实体模型 Controllor:对应于Activity 但是却存在很多问题: 1.这个View对应于布局文件,其实能 ...
- android MVP模式介绍与实战
android MVP模式介绍与实战 描述 MVP模式是什么?MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数 ...
- Android MVP架构分析
App架构在Android开发者中一直是讨论比较多的一个话题,目前讨论较多的有MVP.MVVM.Clean这三种.google官方对于架构的态度一直是非常开放的,让开发者自主选择组织和架构app的方式 ...
- Android MVP模式
转自http://segmentfault.com/blogs,转载请注明出处Android MVP Pattern Android MVP模式\[1\]也不是什么新鲜的东西了,我在自己的项目里也普遍 ...
随机推荐
- 2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest D Dividing Marbles
题目大意: 给出一个$N(N <= 2^{22}$),$N$的二进制表示中1的个数不超过4. 一开始有一个集合$S = {N}$, 每次操作可以选择$n\in S \ (n > 1)$, ...
- 【BZOJ】3433: [Usaco2014 Jan]Recording the Moolympics (贪心)
http://www.lydsy.com/JudgeOnline/problem.php?id=3433 想了好久啊....... 想不出dp啊......sad 后来看到一英文题解......... ...
- mysql_real_connect 端口号说明
mysql_real_connect语法: C++ Code 12345678 MYSQL * mysql_real_connect(MYSQL * mysql, ...
- C++获取某个文件夹下的所有文件
获取某个文件夹下的所有文件,返回各文件的路径加文件名 path为某文件夹的路径:eg. char * filePath = "C:\\Users\\WUQP\\Desktop\\test_d ...
- AEcs6破解版下载
下载地址 http://pan.baidu.com/share/link?shareid=79184520&uk=1795677788 点击下载
- angular做的简单购物车
虽然本人也是刚刚才开始学习angular.js,并不是非常会,但是这并不能阻止我对angular的喜爱.因为它太省代码了,比如说一个比较简单的购物车,就是只有商品名称,单价,数量,小计,总计和删除功能 ...
- Intellij IDEA Ultimate Edition 14.1 破解
key:IDEA value:61156-YRN2M-5MNCN-NZ8D2-7B4EW-U12L4 (2) key:huangwei value:97493-G3A41-0SO24-W57LI-Y2 ...
- learnyou 相关网站
http://learnyouahaskell.com/ http://learnyouahaskell-zh-tw.csie.org/ http://learnyousomeerlang.com/
- 系统根据用户cookies,为用户打上各种标签
DSP营销学院_品友学院 | 品友推广官网 http://e.ipinyou.com/school_article40.html 智能算法+动态出价=最大发挥推广费用的价值 针对每一个曝光进行甄别和竞 ...
- REST Representational state transfer REST Resource Naming Guide Never use CRUD function names in URIs
怎样用通俗的语言解释什么叫 REST,以及什么是 RESTful? - 知乎 https://www.zhihu.com/question/28557115 大家都知道"古代"网 ...