背景
在 Android 开发中,我们都很熟悉 Activity 的 Lifecycle,并且会在特定的 Lifecycle 下执行特定的操作。当然,我们清楚 Lifecycle 本身是带有 Android 特质的,那尝试设想下,如果 普通的 Java Class 也能自动感知
Lifecycle 呢
?咋一听这个想法似乎背后意义不大,但在实际探索中,我们发现这个特性能为我们达成一些之前未考虑到或者不易实现的优化。
本文分享下我们基于这个思想所开发的框架:AutoLifecycle
及其带来的一些有意思的实践。
- 优化一:当 Activity 进入 onDestroy 时,自动取消网络请求返回
- 优化二:自动将网络请求时机提前到 View 渲染之前,提高页面打开速度
- 优化三:MVP 改进,让 Presenter 和 View 自动 bind/unBind
注:下文提到的 Lifecycle-Aware
就是这里指代的 让普通 Java Class 自动获取 Lifecycle
。
实践及优化
优化一:当 Activity 进入 onDestroy 时,自动取消网络请求返回
在网络请求时,相信大家都有一个经验:在每个网络结果回来时,我们做的第一件事不是显示数据,而是写个 if-else 判断 Activity 还在不在。
由于网络请求都是异步的,所以不得不做这样的判断,来防止不可预测的空指针问题或内存泄漏问题。
既然你总是担心 Activity
还在不在,那么如果我们通过 Lifecycle-Aware 让每个网络请求能自动感知 Activity 的 onDestroy 事件
,
并在 onDestroy
时,自动把网络请求结果 取消掉不再返回
,那就能够消除这个担忧了。
其中最关键的就是 compose(bindUntilEvent(ActivityLifecycle.DESTROY))
这句,它能达到的效果是:一旦 Activity
发生 onDestroy
时,Observer
的数据就会停止向 Subscriber
里流动。从而保证 onNext
无需担心 Activity
已Destroy
这种情况。
在上面网络请求的实践里,你还可以根据自己的情况把 Destroy
换成 Stop
/Pause
等,而且可以看出,这种自动取消机制可适用于任何Observable
,不仅仅是网络请求。
优化二:自动将网络请求提前到 View Inflate 之前,加速页面渲染
先说下这项优化的原理。
通常,我们会在 Activity
的onCreate
里依次执行下面的代码:
即在 Inflate View
和初始化 View
之后,才发起网络请求去加载数据。
而实际上,网络请求是不占用主线程的,如果能在 Inflate View
之前就在其他线程发起网络请求,可以把整个页面显示耗时缩短100ms-200ms
。
现在有了 AutoLifecycle
框架,我们就可以很轻松实现:让 Presenter 自动监听 Inflate View
这个生命周期,在那时发起网络请求即可。
|
|
此时,我们的 Activity 也不用手动调用 presenter.loadDataFromServer();
了,因为 Presenter 内会在感知到 Inflate View
事件时自动发起网络请求。
|
|
经过测试,在保证单个网络请求耗时相同的情况下,页面从 onCreate
到显示数据
的渲染耗时可以从 550ms
缩短到 367ms
,也就是30%-40%
的优化,效果是非常不错的,而且代码也更加简洁清晰。
通过简单的注册 AutoLifecycle
,Presenter
能够自动感知到所有Lifecycle
,甚至包括自定义的特殊Lifecycle
,如下图:
优化三:MVP 改进,让 Presenter 和 View 自动 bind/unBind
第一项优化比较直接,可以先让大家形成一个直观印象。
我们项目是采用 MVP 项目,对于 Presenter
的使用存在一段固定代码,即在 onCreate
时调用 bindView()
,在onDestroy
时调用unBindView()
。如下图:
那么,既然我们现在能 让一个普通类自动感知 Lifecycle
,那其实也就能让 Presenter
在感知到 onCreate
时自动 bindView
,在感知到 onDestroy
时自动 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 等。
源码
对源码感兴趣的欢迎进入我的【小专栏 https://xiaozhuanlan.com/wingjay】或者 【付费群 http://www.jianshu.com/p/655af849aaf6】
总结
Lifecycle-Aware
思想是 Google 官方提出来的概念:赋予普通类自动感知生命周期的能力。而本文也是基于这个思想,提供了一些具体实践和优化的思路,读者同学可以根据自己的情况做更多的改进和尝试。
——————
wingjay
谢谢。
欢迎加入【阿里求职付费群】:
- 及时推送集团内最新岗位空缺信息
- 定期分享针对阿里的最新 Android 面试题及相关面试经验
- 长期提供阿里集团内各岗位的内推。
详情:http://www.jianshu.com/p/655af849aaf6
参考
https://developer.android.com/topic/libraries/architecture/lifecycle.html
https://www.atatech.org/articles/63098
https://github.com/trello/RxLifecycle
http://reactivex.io/RxJava/javadoc/rx/subjects/PublishSubject.html
http://reactivex.io/RxJava/javadoc/rx/Observable.Transformer.html