@Tyhj
2020-03-26T21:15:03.000000Z
字数 9024
阅读 1058
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() {
@Override
public 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
的操作,那生命周期变化监听的接口调用应该不是这里触发的;
//ComponentActivity
private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
@Override
public Lifecycle getLifecycle() {
return mLifecycleRegistry;
}
那再看FragmentActivity类,里面重写了getLifecycle
方法,而且在每个生命周期里面都调用了mFragmentLifecycleRegistry.handleLifecycleEvent
方法,看一下这个方法的实现,猜也能猜到最后调用了mLifecycleObserver.onStateChanged(owner, event);
方法,跟着源码看下去的确是这样,该方法在LifecycleRegistry
里面,这里代码没有给出,为了防止出错,中间也经过了一系列比较复杂的判断;不过找了很久都没有找到ON_ANY
这个标准的返回是在哪里触发的,这个感觉是没用的;
//FragmentActivity
final LifecycleRegistry mFragmentLifecycleRegistry = new LifecycleRegistry(this);
@Override
public 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 LifecycleObserver
return 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
@Override
public 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);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = findViewById(R.id.tvName);
//获取用户信息
presenter.getUserInfo();
}
@Override
public 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();
}
@Override
public void getUserInfo() {
//从M层获取用户信息
UserInfo userInfo = mUserInfoModel.getUserInfo();
//调用View层的接口进行信息展示
mIShowUserView.showUserInfo(userInfo);
}
}
这样就实现了一个简单的展示用户信息的功能,如果获取用户信息是一个耗时接口,就会有问题,这里做一个线程处理,在子线程获取用户信息,在主线程进行返回;
@Override
public void getUserInfo() {
AppExecutors.getInstance().getNetworkIo().execute(()->{
//从M层获取用户信息
UserInfo userInfo = mUserInfoModel.getUserInfo();
AppExecutors.getInstance().getMainThread().execute(()->{
//调用View层的接口进行信息展示
mIShowUserView.showUserInfo(userInfo);
});
});
}
这时候如果当这个Activity关闭了,获取操作还没有执行完,会导致什么情况?讲道理View被销毁了,这里是不是应该出现空指针错误,是不是要加判断,判断一下mIShowUserView
是否为空;
@Override
public 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的代码
@Override
public void destroy() {
mIShowUserView=null;
mUserInfoModel=null;
}
}
当Activity被释放的时候调用该方法
@Override
protected 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() {
@Override
public 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层的方法,现在是正常代码
@Override
public void getUserInfo() {
//从M层获取用户信息
mUserInfoModel.getUserInfo(new IDataBackListener<UserInfo>() {
@Override
public void dataBack(UserInfo userInfo) {
//调用View层的接口进行信息展示
Log.e("ShowUserPresenter", "showUserInfo");
//判断View是否为空
if (mIShowUserView != null) {
mIShowUserView.showUserInfo(userInfo);
}
}
@Override
public 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() {
@Override
public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
broken = true;
}
}
});
}
@Override
public void dataBack(T t) {
if (!broken) {
backData(t);
}
}
@Override
public 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对象即可
@Override
public void getUserInfo() {
//从M层获取用户信息
mUserInfoModel.getUserInfo(new BaseDataBackListener<UserInfo>(mLifecycle) {
@Override
public void backData(UserInfo userInfo) {
//调用View层的接口进行信息展示
Log.e("ShowUserPresenter", "showUserInfo");
mIShowUserView.showUserInfo(userInfo);
}
@Override
public void backError(int code, String msg) {
}
});
}
这里不仅仅是减少判空问题,是在View销毁后彻底停止了P层的无效的操作,感觉还是比较有意思的