让普通 Java 类自动感知 Activity Lifecycle
背景
在 Android 开发中,我们都很熟悉 Activity 的 Lifecycle,并且会在特定的 Lifecycle 下执行特定的操作。当然,我们清楚 Lifecycle 本身是带有 Android 特质的,那尝试设想下,如果 普通的 Java Class 也能自动感知 Lifecycle 呢 ?咋一听这个想法似乎背后意义不大,但在实际探索中,我们发现这个特性能为我们达成一些之前未考虑到或者不易实现的优化。java学习群669823128
本文分享下我们基于这个思想所开发的框架: AutoLifecycle 及其带来的一些有意思的实践。
- 优化一:当Activity进入onDestroy时,自动取消网络请求返回
- 优化二:自动将网络请求时机提前到View渲染之前,提高页面打开速度
- 优化三:MVP改进,让Presenter和View自动bind/unBind
注:下文提到的 Lifecycle-Aware 就是这里指代的 让普通 Java Class 自动获取 Lifecycle 。
实践及优化
优化一:当Activity进入onDestroy时,自动取消网络请求返回
在网络请求时,相信大家都有一个经验:在每个网络结果回来时,我们做的第一件事不是显示数据,而是写个if-else判断Activity还在不在。
mTopApiObservable
...
.subscribe(new Subscriber<Object>() {
@Override
public void onNext(Object data) {
if(activity == null) {
return; // 判断Activity是否还在,不在就不去显示数据
}
display(data); // 显示数据
}
...
});
由于网络请求都是异步的,所以不得不做这样的判断,来防止不可预测的空指针问题或内存泄漏问题。
既然你总是担心 Activity 还在不在,那么如果我们通过 Lifecycle-Aware让每个网络请求能自动感知Activity的onDestroy事件 ,
并在 onDestroy 时,自动把网络请求结果 取消掉不再返回 ,那就能够消除这个担忧了。
mTopApiObservable
...
.compose(bindUntilEvent(ActivityLifecycle.DESTROY)) // 绑定Activity的onDestroy事件
.subscribe(new Subscriber<Object>() {
@Override
public void onNext(Object data) {
display(data); // 直接去显示数据
}
...
});
其中最关键的就是 compose(bindUntilEvent(ActivityLifecycle.DESTROY)) 这句,它能达到的效果是:一旦 Activity 发生 onDestroy 时, Observer 的数据就会停止向 Subscriber 里流动。从而保证 onNext 无需担心 Activity 已 Destroy 这种情况。
在上面网络请求的实践里,你还可以根据自己的情况把 Destroy 换成 Stop / Pause 等,而且可以看出,这种自动取消机制可适用于任何 Observable ,不仅仅是网络请求。
优化二:自动将网络请求提前到View Inflate之前,加速页面渲染
先说下这项优化的原理。
通常,我们会在 Activity 的 onCreate 里依次执行下面的代码:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.XXX); // Inflate View
findViewByIds(); // 初始化View
presenter.loadDataFromServer(); // 发起网络请求
}
即在 Inflate View 和 初始化View 之后,才发起网络请求去加载数据。
而实际上,网络请求是不占用主线程的,如果能在 Inflate View 之前就在其他线程发起网络请求,可以把整个页面显示耗时缩短 100ms-200ms 。
LoadBeforeInflate优化效果
现在有了 AutoLifecycle 框架,我们就可以很轻松实现:让Presenter自动监听 Inflate View这个生命周期,在那时发起网络请求即可。
public class NewPresenter {
public NewPresenter(IView iView) {
...
// 向AutoLifecycle注册
AutoLifecycle.getInstance().init(this);
}
// 当Activity Inflate View前自动回调
@AutoLifecycleEvent(activity = ActivityLifecycle.PRE_INFLATE)
private void onHostPreInflate() {
loadDataFromServer(); // 发起网络请求
}
...
}
此时,我们的Activity也不用手动调用 presenter.loadDataFromServer(); 了,因为Presenter内会在感知到 Inflate View 事件时自动发起网络请求。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.XXX);
findViewByIds();
// 无需手动启动网络请求
}
经过测试,在保证单个网络请求耗时相同的情况下,页面从 onCreate 到 显示数据 的渲染耗时可以从 550ms 缩短到 367ms ,也就是 30%-40% 的优化,效果是非常不错的,而且代码也更加简洁清晰。

通过简单的注册 AutoLifecycle , Presenter 能够自动感知到所有 Lifecycle ,甚至包括自定义的特殊 Lifecycle ,如下图:
LifecycleAwarePresenter
优化三:MVP改进,让Presenter和View自动bind/unBind
第一项优化比较直接,可以先让大家形成一个直观印象。
我们项目是采用MVP项目,对于 Presenter 的使用存在一段固定代码,即在 onCreate 时调用bindView() ,在 onDestroy 时调用 unBindView() 。如下图:
public class OldActivity extends BaseActivity {
BasePresenter mPresenter = new BasePresenter();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter.bindView(this); // onCreate时手动bind Presenter 和 IView
}
@Override
protected void onDestroy() {
mPresenter.unbindView(); // onDestroy时手动unBindView
super.onDestroy();
}
}
那么,既然我们现在能 让一个普通类自动感知Lifecycle ,那其实也就能让 Presenter 在感知到onCreate 时 自动bindView ,在感知到 onDestroy 时 自动unBindView 。
改进后的代码如下:
public class NewActivity extends BaseActivity {
NewPresenter mPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = new NewPresenter(this); // 只需要创建即可
}
}
public class NewPresenter {
private IView mIView;
public NewPresenter(IView iView) {
this.mIView = iView;
// 向AutoLifecycle注册即可获得Lifecycle回调
AutoLifecycle.getInstance().init(this);
}
// 当Activity进入onCreate后自动调用
@AutoLifecycleEvent(activity = ActivityLifecycle.CREATE)
private void onHostCreate() {
bindView(mIView);
}
// 当Activity进入onDestroy后自动调用
@AutoLifecycleEvent(activity = ActivityLifecycle.DESTROY)
private void onHostDestroy() {
unBindView();
}
}
其实,在大家的平常开发中,还会存在许多类似 Presenter 的类: 需要在某个特定的Lifecycle下执行一些动作 。这时就可以基于 Lifecycle-Aware 来让这个普通类自动去执行,而不是去每个Activity/Fragment 里写一遍,提高类的内聚性。
AutoLifecycle的核心原理
(TL;DR)
下面介绍下 AutoLifecycle 的关键实现部分,感兴趣的读者可以参考。
1. 让Activity对外发送Lifecycle事件
使用过 RxJava 的同学知道里面有一个 PublishSubject,基于观察者模式,主动发送并接受消息。这里我们用 PublishSubject 来发送Lifecycle事件。见如下:

这里的Lifecycle事件可以自己定义,比如前面提到的PRE_INFLATE事件,是在setContentView之前发送,类似:

2. 感知某个Lifecycle的发生并自动执行回调
上面提了, PublishSubject 不仅能发送消息,还能接受自己的消息。基于这个特点,我们便可以监听每一个LifecycleEvent。如下图:

这里的参数Observable是我们希望被回调的函数,IContextLifecycle是指定的Lifecycle。即当指定的Lifecycle Event发生时,会自动subscribe提供的Observable。
基于这个功能,便可以实现上面场景一和场景二里的 @AutoLifecycleEvent 注解了,即把 @AutoLifecycleEvent 标注的函数包装成一个Observable,通过这个 executeOn 来注册函数的执行生命周期即可。
3. 监听Lifecycle并取消网络请求结果
在场景三里,我们为网络请求的 Observable 提供了一个 Transformer,它能在监听到某个Lifecycle发生时,停止数据流的向下流动。该 Transformer 的核心实现是:

可以看出,当指定的Lifecycle一旦发生,我们网络请求Observable就会停止向下传递数据。
4. 支持自定义Lifecycle,支持Activity/Fragment/DialogFrament等
可以看出, AutoLifecycle 除了支持常规的生命周期,还能支持自定义的特殊生命周期,比如View Inflate前。
另外,上面都是以Activity为例,不过显然这套框架可以灵活扩展,不局限于Activity,还能适用于Fragment、DialogFrament等。
总结
Lifecycle-Aware 思想是Google官方提出来的概念:赋予普通类自动感知生命周期的能力。而本文也是基于这个思想,提供了一些具体实践和优化的思路,读者同学可以根据自己的情况做更多的改进和尝试。java学习群669823128
让普通 Java 类自动感知 Activity Lifecycle的更多相关文章
- idea 新建java类自动补充创建人,创建时间,版本等..
1.先进入 File 2.进入 Editor 找到 File and Code Templates 并点击 3.右侧点击 lncludes 4.第二项 File Header /** * @aut ...
- eclipse debug模式下总是自动跳到ThreadPoolExecutor.java类
1.情景展示 使用eclipse,debug模式运行项目时,总是会调用这个ThreadPoolExecutor.java类,明明没有打断点却自动停止运行. 2.原因分析 在eclipse中,默认是 ...
- mybatis怎样自动生成java类,配置文件?
其实没有什么东西是可以自动生成的,只不过是别人已经写好了,你调用罢了. 所以想要mybatis自动生成java类,配置文件等,就必须要一些配置和一些jar包.当然这些配置也很简单. 为了有个初步的认识 ...
- Java基础进阶:APi使用,Math,Arrarys,Objects工具类,自动拆装箱,字符串与基本数据类型互转,递归算法源码,冒泡排序源码实现,快排实现源码,附重难点,代码实现源码,课堂笔记,课后扩展及答案
要点摘要 Math: 类中么有构造方法,内部方法是静态的,可以直接类名.方式调用 常用: Math.abs(int a):返回参数绝对值 Math.ceil(double a):返回大于或等于参数的最 ...
- 在IDEA中已经配置postgis数据库驱动并且能在Java类中连接数据库,但在servlet中无法连接数据库且导致Tomcat自动断开连接的解决方案
最近在IDEA中用JDBC连接PostgreSQL数据库时遇到了这样一个奇怪的事情: 从PostgreSQL JDBC Driver官网下载好JDBC驱动之后,在IDEA的Project Struct ...
- IDEA Java 类注释、方法注释模板(可实现自动参数使用生成)
JAVA 类文件注释设置 设置地方: 模板 /** * <p> * $description * </p> * * @author Tophua * @since ${DATE ...
- jvm系列(一):java类的加载机制
java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装 ...
- Java类初始化
Java类初始化 成员变量的初始化和构造器 如果类的成员变量在定义时没有进行显示的初始化赋值,Java会给每个成员变量一个默认值 对于 char.short.byte.int.long.float. ...
- 深入研究Java类装载机制
目录 1.为什么要研究java类装在机制? 2.了解类装载机制,对于我们在项目开发中有什么作用? 3.装载实现细节. 4.总结 一.为什么药研究Java类装载机制 java类加载机制,便于我们使用自定 ...
随机推荐
- 什么是PWM信号
PWM信号脉宽调制PWM是开关型稳压电源中的术语.这是按稳压的控制方式分类的,除了PWM型,还有PFM型和PWM.PFM混合型.脉宽宽度调制式(PWM)开关型稳压电路是在控制电路输出频率不变的情况下, ...
- #pragma编译指令
#pragma alignment#pragma anon_struct#pragma argsused#pragma checkoption#pragma codeseg#pragma commen ...
- 编写通用shell脚本启动java项目,适用于多数服务,只需修改服务名即可
文件名:service-user.sh 文件内容: ##shell脚本的头文件必须有#!/bin/sh ##再次配置java环境变量以防报其他错误## java env#jdk安装目录export J ...
- 支持向量机(Support Vector Machine)-----SVM之SMO算法(转)
此文转自两篇博文 有修改 序列最小优化算法(英语:Sequential minimal optimization, SMO)是一种用于解决支持向量机训练过程中所产生优化问题的算法.SMO由微软研究院的 ...
- zoj3954 详细讲解 排序比较单词法
Seven-Segment Display Time Limit: 1 Second Memory Limit:65536 KB A seven segment display, or se ...
- 如何将解压版的tomcat设置为windows 服务启动
在web服务器上通常需要是web容器随开机自动启动,恰好Tomcat可以作为服务启动,只要经过我们简单的配置,就可以将免安装版的Tomcat添加到系统服务中. 首先需要配置以下环境变量: JAVA_H ...
- python装饰器 & flask 通过装饰器 实现 单点登录验证
首先介绍装饰器,以下是一段标注了特殊输出的代码.用于帮助理解装饰器的调用过程. import time def Decorator_one(arg1): info = "\033[1;31; ...
- 从源码看 angular/material2 中 dialog模块 的实现
本文将探讨material2中popup弹窗即其Dialog模块的实现. 使用方法 引入弹窗模块 自己准备作为模板的弹窗内容组件 在需要使用的组件内注入 MatDialog 服务 调用 open 方法 ...
- Spring MVC Ajax 嵌套表单数据的提交
概述 在一些场景里,某个大表单里常常嵌套着一个或若干个小逻辑块,比如以下表单里"设计预审"中包括了一个子模块表单"拟定款项". 在这种情况下该怎么去设计实体类以 ...
- CoreData和SQLite多线程访问时的线程安全问题
数据库读取操作一般都是多线程访问的.在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱.IOS中常用的两种数据持久化存储方式:CoreData和SQLite,两 ...