一、概述

最近对 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 最简单直接的暴力方式

https://github.com/cnneillee/DailyZHIHU/blob/master/app/src/main/java/com/neil/dailyzhihu/presenter/TopicDetailPresenter.java

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 也被终止生命,故而避免了空指针异常的问题!

这里只引用文中的几个框架,详细分析内容,可参见原文!

此文在我的 Github Pages 上同步发布,地址为:Android MVP Presenter 中引发的空指针异常

最新文章

  1. WPF 自定义的窗口拖动
  2. TreeView 使用方法:(在View.Details模式下)
  3. Xamarin.Android之Splash的几种简单实现
  4. &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt; 的作用?
  5. C++智能指针简单剖析
  6. C# 导出到Excel
  7. HighCharts官网更新了!(忠实粉的小声音)
  8. apache开源项目-- Velocity
  9. iOS开发之Runloop(转)
  10. 关于arm-linux-gcc的安装与配置
  11. PE框架学习之道:PE框架——style的配置
  12. Zabbix监控系统功能及基本使用
  13. [html5] 学习笔记-bootstrap介绍
  14. OAuth2.0学习(1-11)新浪开放平台微博认证-使用OAuth2.0调用微博的开放API
  15. lambda 怎么传递ref参数
  16. 20165214 2018-2019-2 《网络对抗技术》Exp1 PC平台逆向破解 Week3
  17. WinForm textbox 全选
  18. Spring:@Cacheable 中condition条件的理解
  19. linux下切换python2和python3(转)
  20. 3D数学读书笔记——3D中的方位与角位移

热门文章

  1. Java实现验证码的制作
  2. Android开发人员必须掌握的10 个开发工具+应该深入学习的10个开源应用项目
  3. 【BZOJ】3299: [USACO2011 Open]Corn Maze玉米迷宫(bfs)
  4. mysql中RAND()随便查询记录效率问题和解决的方法分享
  5. 怎么用ChemDraw 15.1 Pro绘制彩色结构
  6. flask-第三方组件
  7. EditText ------- 键盘类型
  8. poj万人题
  9. java jdk 1.6 下载
  10. Learning PHP Design Patterns