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\]也不是什么新鲜的东西了,我在自己的项目里也普遍 ...
随机推荐
- 嵌入式开发之示波器----tektronix tds2024 的使用
http://jingyan.baidu.com/article/91f5db1bf715c01c7f05e39a.html http://cn.tek.com/learning/oscillosco ...
- 【watcher】 #02 c# 中实现时间戳等,日期数字及大概率绝对随机数 实现
在Wacher的项目中,用到了很多时间记录的地方,为了将来能够和在线数据打通,我们使用了时间戳来记录时间信息 由于c# 没有现成的方法,所以我们重新写了一个Helper类来帮助我们使用这些公共函数 同 ...
- PHP第三方登录
参考视屏:http://www.imooc.com/learn/596 php第三方登录-QQ登录OAuth协议基本原理QQ登录前置条件以及开放平台账号申请1,一个QQ号2,一个公网通过域名可访问的w ...
- 《The Swift Programming Language》的笔记-第24页
The Swift Programming Language读书笔记学习笔记 第24页 本页主要内容有两个:打印输出和怎样在swift凝视代码 1 怎样打印变量和常量的值? 使用println函数,细 ...
- poj 2662(Dijkstra+记忆化)
题目链接:http://poj.org/problem?id=2662 思路:首先路径的选择,如果B点到终点的距离比A点到终点的最短距离短,那么就从A走到B,换句话说,就是每次都是择优选择更靠近终点的 ...
- linux机器之间配置ssh无密访问
首先确认已安装了ssh服务,没装的自行百度一下. A机器:192.168.1.1 B机器:192.168.1.2 使A无密访问B,步骤如下[root@localhost ~]# cd .ssh 如果没 ...
- iOS捕获异常,常用的异常处理方法
本文转载至 http://www.cocoachina.com/ios/20141229/10787.html 前言:在开发APP时,我们通常都会需要捕获异常,防止应用程序突然的崩溃,防止给予用户不友 ...
- simpson公式求定积分(模板)
#include<cstdio> #include<cmath> #include <algorithm> using namespace std; double ...
- selenium 方法导图
- git GUI 入门
一:安装一个git 及gui 二:配置gui及线上的git链接 在Git Gui中,选择Remote->add添加远程服务器,远程服务器信息有两种填写方式,填写https地址或ssh地址,对应g ...