零. 前言

关于Jetpack的组件使用已经很久了,其原理一直处于碎片化接受的状态,最近项目不忙,现进行完整的一次梳理,首先看看The base -- Lifecycle。

一. Everything is based on Lifecycle

Lifecyle的地位在整个架构中处于最底层的基石,有了它才有后续的LiveData和ViewModel。

Lifecyle出现的背景

  1. Android中有一个比较重要的概念 -- 生命周期,大到Application,小至Fragment都会遵循其本身的声明周期规则。
  2. 生命周期感知组件--即需要遵循生命周期规则在特定的生命周期内做对应的事,但它没法直接感知,所以需要借助Activity或者Fragment通过复写其生命周期方法,来进行维护。这种模式有着显而易见的缺陷--代码条理性差、不内聚、使得V层代码越发臃肿。
class MyLocationListener {
    public MyLocationListener(Context context, Callback callback) {
        // ...
    }

    void start() {
        // connect to system location service
    }

    void stop() {
        // disconnect from system location service
    }
}

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    @Override
    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, (location) -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        myLocationListener.start();
        // manage other components that need to respond
        // to the activity lifecycle
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

上面引用官网文档上举的一个例子,希望activity在前台时进行定位的监听,所以复写了onStart()方法和onStop()方法,并分别开始定位和停止定位。
问题:

  1. 实际项目中这种相关场景的依赖生命周期的组件非常多,这无疑是令人头大的。
  2. 此外还有内存泄漏的可能,如果onStart中该组件需要进行耗时操作,则可能出现OnStop方法在onStart方法先走,如此该组件留存时间就会比其所需时间长,这种竞争的情况就可能会导致内存泄漏的情况发生。

二. How to use Lifecycle ?

It's so easy!

step1: 添加依赖:

dependencies {
        def lifecycle_version = "2.2.0"
        def arch_version = "2.1.0"

        // Lifecycles only (without ViewModel or LiveData)
        implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"


        // Annotation processor
        annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
        // alternately - if using Java8, use the following instead of lifecycle-compiler
        implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
    }

step2: 将需要感知生命周期的组件实现对应接口,共3种途径

  1. 实现DefaultLifecycleObserver接口
public interface DefaultLifecycleObserver extends FullLifecycleObserver {
     void onCreate(LifecycleOwner owner);
     void onStart(LifecycleOwner owner);
     void onResume(LifecycleOwner owner);
     void onPause(LifecycleOwner owner);
     void onStop(LifecycleOwner owner);
     void onDestroy(LifecycleOwner owner);
 }
 
 class LocationObserver implements DefaultLifecycleObserver{
     void onStart(LifecycleOwner owner){}
     void onStop(LifecycleOwner owner){}
 }
  1. 继承LifecycleObserver类
//1. 自定义的LifecycleObserver观察者,在对应方法上用注解声明想要观  察的宿主的生命周期事件即可
class LocationObserver extends LifecycleObserver{
    //宿主执行了onstart时,会分发该事件
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void onStart(@NotNull LifecycleOwner owner){
    //开启定位
    }

    //宿主执行了onstop时 会分发该事件
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void onStop(@NotNull LifecycleOwner owner){
        //停止定位
    }
    }
  1. 实现LifecycleEventObserver
class LocationObserver extends LifecycleEventObserver{
     @override
     void onStateChanged(LifecycleOwner source, Lifecycle.Event event){
     //需要自行判断life-event是onstart, 还是onstop
     }
 }

step3:

在生命周期组件中绑定对应生命周期观察者
```
    //2. 注册观察者,观察宿主生命周期状态变化
    class MyFragment extends Fragment{
        public void onCreate(Bundle bundle){
            LocationObserver observer =new LocationObserver()
            getLifecycle().addObserver(observer);
        }
    }
```

至此,如果看到至此,其实你就已经学会了lifecycle的用法了,合理地使用lifecycle可以轻松地管理我们应用的生命周期,优雅地实现业务,结合viewModel和liveData使用会更加酸酸!!

但上述的例子仅仅是lifecyle的基础用法,如果想要玩出更加酷炫的花样,则需要进一步了解其背后的原理。

三. 掀起Lifecycle的盖头来!

1.核心职能类

首先我们先要知道四个核心类,分别为LifecycleOwner、 Lifecycle、 LifecyleRegistry、 LifecycleObserver,他们之间的关系和职能我们用下表来捋一捋。

类名

职责

Lifecycle

一个抽象类,定义了State(宿主状态)、Event(分发的生命周期事件),能添加和移除宿主生命周期的观察者

LifecyleRegistry

Lifecycle的唯一实现类,负责生命周期的注册及分发

LifecycleOwner

生命周期的宿主,持有Lifecycle的类,需要实现getLifecycle方法

LifecycleObserver

感知宿主生命周期的观察者,通过生命周期事件获得对应的宿主生命周期状态

life cycle inventories 博客 life cycle impact assessment_android

上面表格及类图已经清晰地显示了对应几个核心类之间的关系和职责,其中提及到的宿主状态和生命周期事件。


2. 宿舍生命周期状态与生命周期事件

下面我们引用官网上的一幅图来简单描述一下宿主状态和生命周期事件

life cycle inventories 博客 life cycle impact assessment_ide_02

  • State:状态,是Lifecycle中对应Activity生命周期的一种状态标识,共INITIALIZED、DESTROYED、CREATED、STARTED、RESUMED五种状态
  • Event:事件,当State发生变化时,Lifecycle会向已注册的LifecycleObserver发送事件,例如:当State从INITIALIZED变化到CREATED时,就会发出ON_CREATE事件。

经过上面的介绍,我们应该就能看出来,要真正弄懂Lifecycle,其实就是需要弄懂三件事

  1. 状态(State)如何和组件(Activity、Fragment)生命周期绑定的?
  2. 观察者咋注册上的?
  3. 如何分发生命周期事件Event到观察者?

3.Fragment和Activity是如何实现Lifecycle的?

Fragment实现了宿主接口LifecycleOwner,利用注册器LifecycleRegistry进行分发对应的事件给每个观察者

public class Fragment implements LifecycleOwner {
    LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
      @Override
      public Lifecycle getLifecycle() {  
          //复写自LifecycleOwner,所以必须new LifecycleRegistry对象返回
          return mLifecycleRegistry;
      }

    void performCreate(){
         mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
      }

     void performStart(){
         mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
      }
      .....
     void performResume(){
         mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
      }  
}

Activity实现的Lifecycle需要借助一个Fragment--ReportFragment(这是一个透明的Fragment)来用以报告生命周期的变化,这里有一个问题,为什么Activity不直接和Fragment一样直接在对应自身的生命周期方法处分发生命周期事件呢?这个问题在文末解答

public class ComponentActivity extends Activity implements LifecycleOwner{
  private LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);
   @NonNull
   @Override
   public Lifecycle getLifecycle() {
      return mLifecycleRegistry;
   }
  
  protected void onCreate(Bundle bundle) {
      super.onCreate(savedInstanceState);
      //往Activity上添加一个fragment,用以报告生命周期的变化
      //目的是为了兼顾不是继承自AppCompactActivity的场景.
      ReportFragment.injectIfNeededIn(this); 
}

ReportFragment本身没有什么特殊的地方,和Fragment中源码一样,在各个生命周期方法内利用mLifecycleRegistry分发事件。

public class ReportFragment extends Fragment{
    public static void injectIfNeededIn(Activity activity) {
        android.app.FragmentManager manager =  activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), 			  			     		REPORT_FRAGMENT_TAG).commit();
            manager.executePendingTransactions();
    	}
	}
    @Override
    public void onStart() {
        super.onStart();
        dispatch(Lifecycle.Event.ON_START);
    }
    @Override
    public void onResume() {
        super.onResume();
        dispatch(Lifecycle.Event.ON_RESUME);
    }
    @Override
    public void onPause() {
        super.onPause();
        dispatch(Lifecycle.Event.ON_PAUSE);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        dispatch(Lifecycle.Event.ON_DESTROY);
    }
    private void dispatch(Lifecycle.Event event) {
         Lifecycle lifecycle = activity.getLifecycle();
         if (lifecycle instanceof LifecycleRegistry) {
             ((LifecycleRegistry)   lifecycle).handleLifecycleEvent(event);
         }
}

4.观察者咋注册上的?

前面我们已经提到过,LifecycleRegistry--这个唯一实现了Lifecycle的类,它即是一个注册中心兼分发中心,替Activity和Fragment代理了生命周期事件的注册和分发。

(为什么不让Activity自己来做这件事呢?我觉得是为了类的职责单一原则和及迪米特原则,Activity属于View层,它只需要管理如何展示即可。)

public void addObserver(@NonNull LifecycleObserver observer) {
        // 添加新的Observer时,会首先根据宿主的状态计算出它的初始状态,只要不是在onDestroy中注册的,它               // 的初始状态都是INITIALIZED
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    	// 接着会把observer包装成ObserverWithState,这个类主要是包含了观察者及其状态。
        // 每个事件都会经由这个对象类转发,这个类后面会来分析
        ObserverWithState statefulObserver = new ObserverWithState(observer, 					initialState);
    	// 添加到集合,如果之前已经添加过了,则return
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, 						statefulObserver);

        ...

        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
    	//这里的while循环,是实现上图状态同步与事件分发的主要逻辑
        //拿观察者的状态和宿主当前状态做比较,如果小于0,说明两者状态还没有对齐。
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            // 将statefulObserver的状态push进mParentStates列表
            pushParentState(statefulObserver.mState);
            // 接着就会分发一次相应的事件,于此同时statefulObserver的mState对象也会被升级
            // 假设是在宿主的onresume方法内注册的该观察者
            // 第一次:分发on_Create事件,观察者状态INIT->CREATED 
            // 第二次:分发on_Start事件,观察者状态CREATED->STARTED 
            // 第三次:分发on_Resume事件,观察者状态STARTED->RESUMED
            statefulObserver.dispatchEvent(lifecycleOwner,	                         				upEvent(statefulObserver.mState));
            // 将statefulObserver的状态从mParentStates列表中移除
            popParentState();
            // 再一次计算观察者应该到达的状态,在下一轮循环中和宿主状态在做比较,知道两者状态对齐,退出				   // 循环。
            targetState = calculateTargetState(observer);
        }

        ...
    }

    /**
     * 计算目标State
     * 由于要保持“不变性”,被计算的observer的State必要小于等于mObserverMap中最后一个LifecycleObserver的		 * State、mState、parentState三者中最小的一个State
     */
private State calculateTargetState(LifecycleObserver observer) {
    Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);

    State siblingState = previous != null ? previous.getValue().mState : null;
    State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
        : null;
    return min(min(mState, siblingState), parentState);
}

上面这段代码则是LifecycleRegistry添加一个观察者需要做的事。

在理解上述代码之前,需要有三个观念:

  • State从INITIALIZED到RESUMED状态是增大的过程(State这个枚举类也是按此特定顺序排列的)。
  • 存储观察者的数据结构,是一个链表实现的Map,因为在我们遍历观察者列表的时候,观察者可能随时被移除。
  • "不变性" -- 先添加的观察者observer1的状态state1,永远要比后添加的观察者observer2的状态state2大,即state1 >= state2。(原因:新添加的observer初始State是INITIALIZED,如果当前宿主处于onResume,那么需要将该观察者的状态State从INITIALIZED增大为RESUMED,因此mObserverMap中原先已经添加的LifecycleObserver的State肯定>=INITIALIZED)

疑问1:mParentStates这个列表的作用是什么?为什么计算目标State时,需要取观察者列表中最后一个观察者的State、宿主当前的State、mParentStates最后一个State中的最小值?

// we have to keep it for cases: // void onStart() { // mRegistry.removeObserver(this); // mRegistry.add(newObserver); // }

上面的例子很好地解释了这个问题,假如我在onStart方法中移除了当前观察者,而同时我又添加了一个新地观察者,这时新的观察者理应从初始状态被增大至Created状态,但是由于我们在onStart方法中移除了当前观察者,我们从mObserverMap中无法找到移除的当前观察者,则此时则无法保证"不变性"。

疑问2:为什么要将LifecycleObserver封装成ObserverWithState对象?

static class ObserverWithState { State mState; LifecycleEventObserver mLifecycleObserver; ObserverWithState(LifecycleObserver observer, State initialState) { // 兼容多种LifecycleObserver mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer); mState = initialState; } void dispatchEvent(LifecycleOwner owner, Event event) { // 再一次根据需要分发的事件类型反推出该观察者的状态 State newState = getStateAfter(event); mState = min(mState, newState); mLifecycleObserver.onStateChanged(owner, event); mState = newState; } }

ObserverWithState是一个携带着状态的生命周期观察者类,其职责仅有一点:

  • 将传入的LifecycleObserver转化为LifecycleEventObserver,前面我们提到过观察者共有三种类型,每种类型接受事件的形式不一样,需要在分发事件的收口点做一个兼容转化。


life cycle inventories 博客 life cycle impact assessment_ide_03


5. 生命周期事件Event如何通知到注册的生命周期观察者?

生命周期事件的分发过程如下:

public void handleLifecycleEvent(@NonNull Lifecycle.Event event){      
        //宿主的每个生命周期的变化都会分发一个对应的Lifecycle.Event,走到这里
        //此时会根据需要分发的事件反推出 宿主当前的状态
        State next = getStateAfter(event);
        moveToState(next);
    }

private void moveToState(State next) {
        ...
        mState = next;
        sync();
        ...
}

/**
* 判断所有观察者是否已经“同步”
* 同步的意思是所有的观察者都处于相同的状态
* 由之前说的“不变性”可知,最新的观察者和最老的观察者的状态如果相等,则足以说明已经同步
*/
private boolean isSynced() {
    if (mObserverMap.size() == 0) {
        return true;
    }
    State eldestObserverState = mObserverMap.eldest().getValue().mState;
    State newestObserverState = mObserverMap.newest().getValue().mState;
    return eldestObserverState == newestObserverState && mState ==      		newestObserverState;
}

// moveToState方法只是将传入的宿主新的state和前持有宿主状态作比对,然后保存一下。
//如果宿主状态有变动,则调用sync方法来完成事件的分发和观察者状态的同步
private void sync() {
        while (!isSynced()) {
        //如果宿主当前转态 小于 mObserverMap集合中最先添加的那个观察者的状态
        //则说明宿主可能发生了状态回退,比如当前是RESUMED状态,执行了onPause则回退到STARTED状态
        //此时调用backwardPass把集合中的每个一观察者分发一个on_pause事件,并同步它的状态。
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            }
		//如果宿主当前转态 大于 mObserverMap集合中最先添加的那个观察者的状态
        //则说明宿主可能发生了状态前进,比如当前是STARTED状态,执行了onResume则前进到RESUMED状态
        //此时调用forwardPass把集合中的每个一观察者分发一个on_resume事件,并同步它的状态。
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
    }

LifecycleRegistry在收到handleLifecycleEvent()后,内部调用moveToState()方法,改变State值,每一次State值改变,都会调用LifecycleObserver.onStateChanged()方法将Event分发到LifecycleObserver

其实需要完成的事情很简单:就是先改变LifecycleRegistry的状态,然后把状态“同步”到所有的观察者,代码中时刻都在维护着我们前面提到的"不变性",这个规则给我们去判断是否同步完成的依据。

四. Lifecyle其他的酷炫玩法

  1. 监听应用前后台切换:ProcessLifecycleOwner -- Lifecyle的成员之一可以帮助你轻松做到
  2. 自动处理生命周期的Handler:将Handler实现LifecycleObserver接口并给其提供一个需要感知的LifecycleOwner 对象,在接收到ON_DESTROY事件时移除监听。
  3. 免反注册事件监听的事件总线: LiveDataBus, 及其约束进阶版
  4. 结合ViewModel & dataBinding, 优雅地实现MVVM架构
  5. 自动处理生命周期的Service:LifecycleService

五. 总结

Lifecycle本质上就是一个观察者模式的完美诠释,它成功地解耦了需要监听生命周期的组件与Activity或Fragment之间的依赖关系,免去了手动管理生命周期的困难,减少了内存泄漏的风险。

拥抱Jetpack,拥抱未来!