@Tyhj
2020-03-26T13:15:03.000000Z
字数 9024
阅读 1260
Android
Jetpack 是Google官方的一套库、工具和指南,可帮助开发者更轻松地编写优质应用。这些组件可帮助您遵循最佳做法、让您摆脱编写样板代码的工作并简化复杂任务,以便您将精力集中放在所需的代码上。
Jetpack 包含与平台 API 解除捆绑的 androidx.* 软件包库。这意味着,它可以提供向后兼容性,且比 Android 平台的更新频率更高,以此确保您始终可以获取最新且最好的 Jetpack 组件版本。
Lifecycles是JetPack中的一个组件,主要功能就是可以监听Activity和Fragment的生命周期;作用就是可以将一些在Activity中,和Activity生命周期相关的操作下放到具体的组件功能中去;目的在于减少Activity和其它组件的耦合,这些组件可以根据 Activity 或 Fragment 的当前生命周期状态自动调整其行为。
使用是非常简单的,ShowUserActivity继承AppCompatActivity,调用getLifecycle()方法就可以获取到Lifecycle对象然后添加生命周期监听,onStateChanged方法会返回生命周期的变化值
//注册对Activity的生命周期变化的监听ShowUserActivity.this.getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {switch (event) {case ON_CREATE:case ON_START:case ON_RESUME:case ON_PAUSE:case ON_STOP:case ON_DESTROY:case ON_ANY:default:break;}}});
ShowUserActivity继承关系->AppCompatActivity->FragmentActivity->ComponentActivity;看getLifecycle()方法是ComponentActivity提供的方法,而这个方法是ComponentActivity实现LifecycleOwner接口里面的方法;方法返回的是一个LifecycleRegistry对象,是ComponentActivity的一个成员变量,但是在ComponentActivity类的生命周期里面并没有做什么关于操作mLifecycleRegistry的操作,那生命周期变化监听的接口调用应该不是这里触发的;
//ComponentActivityprivate final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);@Overridepublic Lifecycle getLifecycle() {return mLifecycleRegistry;}
那再看FragmentActivity类,里面重写了getLifecycle方法,而且在每个生命周期里面都调用了mFragmentLifecycleRegistry.handleLifecycleEvent方法,看一下这个方法的实现,猜也能猜到最后调用了mLifecycleObserver.onStateChanged(owner, event);方法,跟着源码看下去的确是这样,该方法在LifecycleRegistry里面,这里代码没有给出,为了防止出错,中间也经过了一系列比较复杂的判断;不过找了很久都没有找到ON_ANY这个标准的返回是在哪里触发的,这个感觉是没用的;
//FragmentActivityfinal LifecycleRegistry mFragmentLifecycleRegistry = new LifecycleRegistry(this);@Overridepublic Lifecycle getLifecycle() {// Instead of directly using the Activity's Lifecycle, we// use a LifecycleRegistry that is nested exactly outside of// when Fragments get their lifecycle changed// TODO(b/127528777) Drive Fragment Lifecycle with LifecycleObserverreturn mFragmentLifecycleRegistry;}...protected void onStart() {...mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);}...
其实仔细看还是比较简单的,就是写了一个LifecycleEventObserver接口,提供一个返回Activity生命周期状态的方法,然后在Activity的父类里面提供一个LifecycleRegistry对象,这个对象维护一个LifecycleEventObserver接口的集合,可以注册监听接口进来添加到集合里面,当生命周期变化的时候,拿到集合中的LifecycleEventObserver接口对象,调用onStateChanged方法,返回当前的生命周期;
//LifecycleEventObserver接口public interface LifecycleEventObserver extends LifecycleObserver {/*** Called when a state transition event happens.** @param source The source of the event* @param event The event* 返回Activity生命周期的状态*/void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event);}
原理知道了,其实自己去实现也很简单;我们想要实现类似的功能,不只是监听Activity的生命周期,可以监听任何一个组件的信息,在这个基础上实现也是比较简单的,只需要类继承LifecycleOwner接口就可以了,当然这里面我们还是使用了LifecycleRegistry实现,所以返回的生命周期数据也只能是Activity生命周期对应的Lifecycle.Event对象,如果想要实现返回其他类型的生命周期,重写一下LifecycleRegistry就可以了
public class LifecycleDog implements LifecycleOwner {private LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);@NonNull@Overridepublic Lifecycle getLifecycle() {return lifecycleRegistry;}/*** 模拟生命周期*/private void onStart(){lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);}/*** 模拟生命周期*/private void onStop(){lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);}}
举个例子,一个界面需要获取用户信息进行展示,以MVP架构为例,首先是抽象出 View层和Presenter层的接口,View层的功能就是展示用户信息,所以抽象出展示用户信息的接口,用于给P层调用;Presenter层功能是从Model层取用户信息,所有抽象出获取用户信息的接口,用于给View层调用;Model层是获取用户信息,不管是从网络还是数据库取,先不用管
public interface ShowUserContract {/*** 显示用户信息抽象类*/interface IShowUserView {/*** 展示用户信息** @param userInfo*/void showUserInfo(UserInfo userInfo);}/*** 获取用户信息抽象类*/interface IShowUserPresenter {/*** 获取用户信息*/void getUserInfo();}}
然后在View层,也就是Activity里面去实现接口,在Activity启动的时候取获取用户信息,调用P层的接口取获取用户信息,进行展示
public class ShowUserActivity extends AppCompatActivity implements ShowUserContract.IShowUserView {TextView mTextView;/*** P层的引用*/private ShowUserPresenter presenter = new ShowUserPresenter(this);@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mTextView = findViewById(R.id.tvName);//获取用户信息presenter.getUserInfo();}@Overridepublic void showUserInfo(UserInfo userInfo) {if (userInfo != null) {//展示用户信息mTextView.setText(userInfo.getName());}}}
在P层,同样也实现获取用户信息的接口
public class ShowUserPresenter implements ShowUserContract.IShowUserPresenter {/*** View层的引用*/private ShowUserContract.IShowUserView mIShowUserView;/*** M层的引用*/private UserInfoModel mUserInfoModel;public ShowUserPresenter(ShowUserContract.IShowUserView IShowUserView) {mIShowUserView = IShowUserView;mUserInfoModel = new UserInfoModel();}@Overridepublic void getUserInfo() {//从M层获取用户信息UserInfo userInfo = mUserInfoModel.getUserInfo();//调用View层的接口进行信息展示mIShowUserView.showUserInfo(userInfo);}}
这样就实现了一个简单的展示用户信息的功能,如果获取用户信息是一个耗时接口,就会有问题,这里做一个线程处理,在子线程获取用户信息,在主线程进行返回;
@Overridepublic void getUserInfo() {AppExecutors.getInstance().getNetworkIo().execute(()->{//从M层获取用户信息UserInfo userInfo = mUserInfoModel.getUserInfo();AppExecutors.getInstance().getMainThread().execute(()->{//调用View层的接口进行信息展示mIShowUserView.showUserInfo(userInfo);});});}
这时候如果当这个Activity关闭了,获取操作还没有执行完,会导致什么情况?讲道理View被销毁了,这里是不是应该出现空指针错误,是不是要加判断,判断一下mIShowUserView是否为空;
@Overridepublic void getUserInfo() {AppExecutors.getInstance().getNetworkIo().execute(()->{//从M层获取用户信息UserInfo userInfo = mUserInfoModel.getUserInfo();SystemClock.sleep(5000);AppExecutors.getInstance().getMainThread().execute(()->{//调用View层的接口进行信息展示Log.e("ShowUserPresenter","showUserInfo");//判断View是否为空if(mIShowUserView!=null){mIShowUserView.showUserInfo(userInfo);}});});}
其实这是有问题的,因为在线程里面持有mIShowUserView对象的强引用,线程没有结束mIShowUserView是不会被释放的,只是会造成内存泄漏;还有个问题,View持有Presenter的引用,Presenter也持有View的引用;在循环引用的情况,如果JVM的回收方式是引用计数法,那么也会造成两个对象都无法被回收,所以即使获取数据的线程结束了,对象也没法被回收;但是如果JVM的回收方式是可达性分析,那么不存在循环引用回收不掉问题,在这个例子里面问题不是特别大,线程结束后对象自然会被释,但是如果是一个会被反复打开的Activity或者线程的执行操作很长,就会造成更严重的内存泄漏;目前大多数JVM回收方式都是引用计数法
为了避免内存泄漏,界面被关闭就需要去手动释放掉Presenter里面的View对象,与此同时,Presenter调用View的接口的时候就需要判断View是否为空了;在Presenter中添加释放View的代码
@Overridepublic void destroy() {mIShowUserView=null;mUserInfoModel=null;}}
当Activity被释放的时候调用该方法
@Overrideprotected void onDestroy() {super.onDestroy();//对presenter进行释放presenter.destroy();}
Presenter对象的释放在View中进行,View层其实只应该关心界面交互,其实这个操作对View本身来说是不应该关心的,操作较多了也会导致View层的代码比较的复杂难以维护;如果使用Lifecycles就可以让Presenter自己去处理资源释放的问题;只需要修改一下Presenter的构造函数就可以了,监听到Activity销毁的时候进行资源释放;
public ShowUserPresenter(ShowUserContract.IShowUserView IShowUserView,Lifecycle mLifecycle) {mIShowUserView = IShowUserView;mUserInfoModel = new UserInfoModel();mLifecycle.addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {if(event==Lifecycle.Event.ON_DESTROY){destroy();}}});}
同样View层使用的时候传入Lifecycle对象,也不需要再去释放Presenter;
/*** P层的引用*/private ShowUserPresenter presenter = new ShowUserPresenter(this,getLifecycle());
只是一个非常简单的例子,在实际的编码中,还是非常有用的;
上面的例子,虽然解决了在View层释放Presenter的问题,但是我们的Presenter中还是会有很多的判断View是否为空的操作,这种代码无脑重复,又不能不写,感觉太冗余了;利用Lifecycles其实也是可以解决的,实现稍微复杂一点,但是用起来就比较舒服了;
现在我们模拟实现一下Model层获取数据的操作,一般获取数据,我们也会定义一个数据返回监听的接口,定义的比较简单,就是一个泛型的数据返回
public interface IDataBackListener<T> {/*** 获取到数据** @param t*/void dataBack(T t);/*** 返回出错信息** @param code* @param msg*/void error(int code, String msg);}
M层的实现如下
public class UserInfoModel {/*** 获取用户ID** @return*/public void getUserInfo(IDataBackListener<UserInfo> listener) {//模拟耗时操作SystemClock.sleep(5000);UserInfo userInfo=new UserInfo();//返回用户数据listener.dataBack(userInfo);}}
Presenter的获取用户信息的实现方法修改一下,为了好看,我把线程切换去掉了,到这一步代码看起来比之前复杂,是因为刚才没认真写M层的方法,现在是正常代码
@Overridepublic void getUserInfo() {//从M层获取用户信息mUserInfoModel.getUserInfo(new IDataBackListener<UserInfo>() {@Overridepublic void dataBack(UserInfo userInfo) {//调用View层的接口进行信息展示Log.e("ShowUserPresenter", "showUserInfo");//判断View是否为空if (mIShowUserView != null) {mIShowUserView.showUserInfo(userInfo);}}@Overridepublic void error(int code, String msg) {}});}
想要这里不判空,方法只有一个,监听到View被销毁的时候,取消dataBack方法的调用就可以了;那么感觉是需要在UserInfoModel里面操作,P层倒是无所谓,但是M层只是数据层,我感觉不应该牵扯到这些业务;可以这样做,写一个抽象类,继承IDataBackListener数据返回监听接口;在这个类里面,M层调用已实现方法返回数据,P层实现抽象方法接收数据;构造函数传入Lifcycle对象,设置生命周期变化监听,当View被销毁时,设置标志位为false,P层的方法就不会被调用,从而解决了当数据返回View是否还存在问题;
public abstract class BaseDataBackListener<T> implements IDataBackListener<T> {/*** 操作终止*/private boolean broken = false;public BaseDataBackListener(Lifecycle lifecycle) {lifecycle.addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {broken = true;}}});}@Overridepublic void dataBack(T t) {if (!broken) {backData(t);}}@Overridepublic void error(int code, String msg) {if (!broken) {backError(code, msg);}}/*** 返回数据** @param t*/public abstract void backData(T t);/*** 返回错误** @param code* @param msg*/public abstract void backError(int code, String msg);}
P层使用的时候传入Lifecycle对象即可
@Overridepublic void getUserInfo() {//从M层获取用户信息mUserInfoModel.getUserInfo(new BaseDataBackListener<UserInfo>(mLifecycle) {@Overridepublic void backData(UserInfo userInfo) {//调用View层的接口进行信息展示Log.e("ShowUserPresenter", "showUserInfo");mIShowUserView.showUserInfo(userInfo);}@Overridepublic void backError(int code, String msg) {}});}
这里不仅仅是减少判空问题,是在View销毁后彻底停止了P层的无效的操作,感觉还是比较有意思的