打造一个生命周期感知的MVP架构
很久没写Blog了,这两年也积累了比较多的知识和总结。也实现了不少的业务,以及针对部分业务的优化,发现呢有些知识还是可以分享出去的,只是之前一直在纠结会不会被人看不起什么的,之后才发现多虑了。毕竟放出去之后,不同程序员的思维集合起来,也许这个框架还能发展得更加快速、稳定。
可能之后都会两天一更,或者一星期两篇文章这样的速度更新下下。
感慨不多说了,首先放出自己写的一个生命周期感知的MVP架构
(PS:当前的架构是直接运用到一个线上项目了,成果也颇丰,结合自己封装的BaseMVPActivity,BaseMVPFragment一套组件使用,也是美滋滋的。)
生命周期感知的MVP?幌子?还是单纯的MVP?
什么是MVP?能点进来的小伙伴我都相信你都用过MVP了。
至于什么是生命周期感知?先看看这样一个场景:
在Presenter层处理业务逻辑,多多少少会涉及到网络请求,假若你用的是OkHttp、抑或是Retrofit+RxJava作为网络请求,那么就会存在异步请求回调UI的情况,但是我们知道OkHttp他不是和Context生命周期绑定的(阅读源码),Retrofit+RxJava也是的,除非你自己加上了RxLifeCycle的组件支持,但是RxLifeCycle有个问题,我需要bindActivity,那么这个Activity怎么传递进去呢?
原本MVP的设计模式,就是让Presenter层是无法感知View层的Context存在的,假若打通了这个流程,无异于增加了MVP的复杂度。
以下是RxLifeCycle使用(这个bindActivity的对象需要怎么传递呢?)
myObservable
.compose(RxLifecycleAndroid.bindActivity(lifecycle))
.subscribe();
那么问题就来了,因为我Presenter层是不知道Activity或者Fragment的生命周期的,假若在请求回调的期间,我的Activity或者Fragment需要销毁了,但是由于请求回调占用着View层,那么我们的Activity和Fragment就出现了内存泄漏,内存多处泄漏的情况下,还可能直接出现空指针异常(因为泄漏的Activity部分的控件可能已经被回收了,但是继续调用View层控件。)那么App就直接crash掉了。
我们都知道OkHttp里面的请求是可以通过
OkHttpClient.dispatcher().cancelAll()
去取消请求,而Retrofit+Rxjava 就可以通过Observer中的onSubscribe函数,通过一个Disposable列表记录请求,然后在合适的时机去遍历取消就Ok了。
合适的时机?合适的时机在哪里了?
用脚趾头扣动了脑袋瓜想想,也就只有在Activity或者Fragment的onDestory回调的时候了。
时机找到了,生命周期怎么才能从View层传递到Presenter层呢?恰逢AndroidJetPack(后面迭代后改成AndroidX了)的诞生,使我有这个想法封装了一个LifeCycleMVP的框架。
Google地址:https://developer.android.com/jetpack/
因为公司可以翻墙,所以看的都是英文文档。关于JetPack的组件,我会另外开一个篇章去写。
LifeCycle作为Google JetPack 框架下的一个构建工具,Google也是心疼Android开发者,深知Android开发中Activity和Fragment生命管理的问题。特意除了一套LifeCycle供我们使用。
这上面的意思大概就是:LifeCycle是一个轻量的生命周期管理组件,通过监听回调的方式,实现生命周期的监听与回调。例如管理Activity和Fragment的生命回调。
实际上用着也很好用,很简单。因为在AppCompatActivity里面就支持了LifeCycle组件了。所以两三句代码就搞掂了生命周期的响应了
暂时先说下LifeCycle组件的三个类:
LifeCycleOwner:生命周期持有者,一个接口。用于提供生命周期相关回调(Activity的提供实现最后在一个叫SupportActivity,里面就实现了当前接口,用于提供当前LifeCycleOwner对象)
LifeCycleObserver:生命周期观察者,一个接口,用于实现并监听生命周期回调
LifeCycleRegistery:生命周期注册表,主要是关联生命持有者和观察者、控制事件回调给哪个观察者、生命周期绑定处理等。
详细的实现可以自己看看源码(不会很复杂),也可以跳转到这里:待补充
gradle引用:compile "android.arch.lifecycle:extensions:1.1.1"
前戏做足,现在就是撸代码的时刻了。
首先MVP开发模式中,我们先定义一套MVP层的协议,IBaseView,IBasePresenter。
定义一个IBaseView的接口先,可以用于统一管理View层对象。
实现什么函数无伤大雅,可以根据自己业务需求实现。
IBaseView.java
/**
* @Author:Rayman
* @Date:2018/10/17
* @Description: View实现的接口
*/
public interface IBaseView {
/**
* 显示错误,比如无数据、网络错误等等。
*
* @param msg 错误文案提示
*/
void showErrorMsg(String msg);
}
View层回调自己弄,Presenter层回调才是关键。Presenter层我定义的函数有四个:
绑定View、View层onCreate回调(考虑到有的P层需要用到该生命周期回调)、View层onDestroy回调、其他生命周期回调
IBasePresenter.java
/**
* @Author:Rayman
* @Date:2018/10/17
* @Description:Presenter的接口 .
* 默认实现AndroidX LifeCycle组件
**/
public interface IBasePresenter<T> extends LifecycleObserver {
/**
* 绑定View
*
* @param view
*/
void setView(@NonNull T view);
/**
* View层OnCreate事件回调
*/
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void onViewCreate();
/**
* View层onDestroy事件回调
*/
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void onViewDestroy();
/**
* 生命周期切换时候回调
*/
@OnLifecycleEvent(Lifecycle.Event.ON_ANY)
void onLifeCycleChange(@NonNull LifecycleOwner owner,
@NonNull Lifecycle.Event event);
}
按照上面定义完成之后,初步的LifeCycleMvp框架是出来了,剩下的就是怎么走一个MVP的流程和怎么实现生命周期的绑定。
绑定生命周期
绑定生命周期这个呢~需要配合BaseActivity或者BaseFragment使用。
我这里就放出一个BaseMVPActivity,其他情况的使用也是如此。
主要是继承了BaseActivity,然后实现了IBaseView接口,内部还创建了一个IBasePresenter的成员变量。
然后在onCreate生命周期回调的时候,进行View层和Presenter的绑定,同时也绑定生命周期
/**
* @Author:Rayman
* @Date:2018/10/17
* @Description:继承BaseActivity,整合MVP架构
*/
public abstract class BaseMvpActivity<D> extends BaseActivity implements IBaseView<D> {
/**
* description:MVP层关联
**/
private IBasePresenter mPresenter;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
initMvp();
super.onCreate(savedInstanceState);
}
/**
* 初始化MVP架构
*/
private void initMvp() {
mPresenter = createPresenter();
if (mPresenter != null) {
mPresenter.setView(this);
// 初始化MVP的时候,添加生命周期监听
getLifecycle().addObserver(mPresenter);
}
}
/**
* 设置当前模块的P层,需要在initView之前调用
*
* @return
*/
protected abstract IBasePresenter createPresenter();
}
生命周期绑定之后,就剩下使用了。
如何使用?
首先实现一个业务逻辑的Presenter层,然后继承IBasePresenter。
为了方便演示,我随便拿了项目的一个Contract类
IUserChangeAccountContract.java
/**
* @Author:Rayman
* @Date:2018/10/21
* @Description:用户模块---更换账号
*/
public interface IUserChangeAccountContract {
interface IUserChangeAccountModel {
/**
* description:更换账号
**/
Observable<CommonData> changeAccount(String realName , String account);
}
interface IUserChangeAccountPresenter extends IBasePresenter<IUserBindAliAccountView> {
void changeAccount(String realName , String account);
}
// 当前这个IBaseLoadingView也是继承IBaseView的。
interface IUserChangeAccountView extends IBaseLoadingView<CommonData> {
void changeAccountSuccess(String msg);
}
}
然后再看看IUserChangeAccountPresenter的实现
UserChangeAccountPresenter.java
/**
* @Author:Rayman
* @Date:2018/10/21
* @Description:用户模块---P层---更换账号
*/
public class UserBindAliAccountPresenter implements IUserBindAliAccountContract.IUserBindAliAccountPresenter {
private IUserBindAliAccountContract.IUserBindAliAccountView mView;
private IUserBindAliAccountContract.IUserBindAliAccountModel mModel = new UserBindAliAccountModel();
private ArrayList<Disposable> mDisposableList = new ArrayList();
private int requestCount = 0;
@Override
public void setView(IUserBindAliAccountContract.IUserBindAliAccountView view) {
mView = view;
}
@Override
public void onViewCreate() {
LogUtils.error("View创建");
}
@Override
public void onViewDestroy() {
for(int i = 0,size = mDisposableList.size();i < size; i++){
Disposable disposed = mDisposableList.get(i);
disposed.dispose();
}
LogUtils.error("View销毁请求:" + requestCount);
}
@Override
public void onLifeCycleChange(LifecycleOwner owner, Lifecycle.Event event) {
LogUtils.error("View生命周期变换:" + event.name());
}
@Override
public void changeAccount(String realName,String account) {
mView.showLoading();
requestCount++;
mModel.changeAccount(realName, account)
.subscribe(new RxSubscriber<CommonData, IUserBindAliAccountContract.IUserBindAliAccountView>(mView) {
@Override
public void onSubscribe(Disposable d) {
super.onSubscribe(d);
mDisposableList.add(d);
}
@Override
public void onNext(CommonData t) {
super.onNext(t);
mView.bindAliAccountSuccess("绑定成功");
UserUtils.updateBindAccount(account, realName);
}
});
}
}
整个流程就是这样了,上面的例子我就是用Retrofit+RxJava的方式请求的。然后在onSubscribe中将RxJava的事件处理添加到一个列表,然后在ViewDestroy的时候遍历销毁。
最后我们来看下Log的输出还有通过AndroidProfiler查看下,多个请求是否会引起Activity内存泄漏。
待补充----
好了~代码就上面所述的,联动下一篇---基于LifeCycleMvp再扩展,然后发布一个GitHub的开源库。