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\]也不是什么新鲜的东西了,我在自己的项目里也普遍 ...
随机推荐
- Transporting Data Between Database
The Export utility can provide a logical backup of: Database objects A tablespace An entire database ...
- IntelliJ IDEA2017 java连接mysql数据库并查询数据
最近自己开始重新学习java基础了,做java开发不可避免要处理数据库,由于好久不写java了,对idea也有点陌生了.所以这里写篇用jdbc来连接mysql的文章 至于mysql怎么装,请自行百度 ...
- git登陆迁移 SourceTree 不能自动识别
公司切换了迁移了git登陆,具体是什么 我也不是很清楚,结果就是,周一上班 好多小伙伴的git 用不了了,办公室里自然是哀嚎一片, 运维小伙伴给出的解决方案是:改个密码就好啦: 于是照做 结果Sour ...
- lighttpd mysql php简单教程
lighttpd mysql php简单教程 lighttpd+php5+mysql+Debian etch lighttpd是速度最快的静态web server,mysql最通用的的database ...
- c++ 指针(不断更新)
c++指针只能说博大精深,在用的时候感觉好晕 1.指针类型转换 /* 在指针的强制类型转换:ptr1=(TYPE*)ptr2中,如果sizeof(ptr2的类型)大于sizeof(ptr1的类型), ...
- 记Spring-SpringMVC-Mybatis框架搭建
1.spring相关架包的下载 云盘下载地址:https://pan.baidu.com/s/1o8sk8Ee 官网下载地址:http://repo.springsource.org/libs-rel ...
- Spring容器初始化的时候如何添加一个定时器?
昨天遇到这个问题,在项目启动的时候添加一个定时器隔一段时间扫描有没有定时发送的邮件(当然也可以是你自己的业务逻辑),也在网上找了资料,加上自己的修改,终于成功了.所以来做个记录. 1.ServletC ...
- Visual Assist X助手的一些使用技巧和快捷键
部分快捷键 Shift+Alt+F // Find References 查找引用 Shift+Alt+S // FindSynbolDialog打开查找符号对话框 Alt+G // GotoImpl ...
- 并发编程8 线程的创建&验证线程之间数据共享&守护线程&线程进程效率对比&锁(死锁/递归锁)
1.线程理论以及线程的两种创建方法 2.线程之间是数据共享的与join方法 3.多线程和多进程的效率对比 4.数据共享的补充线程开启太快 5.线程锁 互斥锁 同步锁 6.死锁现象和递归锁 7.守护线程 ...
- javascript的解析过程
引言: javascript是一种解释型的脚本语言,它不同于java或者c#这种编译语言,不需要编译成游览器可识别的语言,而是由游览器动态解析和执行的.(本身就是游览器可以直接识别,javascrip ...