JetPack | Lifecycle 如何做到感知生命周期

LifeCycle的作用是什么:生命周期感知型组件可执行操作来响应另一个组件(如 Activity 和 Fragment)的生命周期状态的变化。这些组件有助于您编写出更有条理且往往更精简的代码,此类代码更易于维护(摘自Android官网的解释)。 Lifecycle 最早是在 support 26.1.0 时被引入的,目前已经成为源码的一部分,而几乎无需使用者在 Gradle 额外地配置依赖。 Lifecycle的出现,可以帮助我们感知生命周期。

关于LifeCycle的使用这里不在复述直接看官方文档,本篇文章旨在理解Lifecycle的本质以及优秀代码的设计思想。

Lifecycle出现的背景原因

在LifeCycle没有出现之前,如果外部类要先监听Activity/Fragment的生命周期,需要定义个接口来监听Activity的生命周期方法(onCreate onStart onResume)等。避免内存泄漏等问题。 如下代码:随着Activity的功能越来越复杂,Listener处理的事情就会越来越多,最终导致代码难以维护。

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
    }
}

那么Lifecycle是如何实现组件的隔离呢?

Lifecycle 实现隔离

在Android的官方文档中看到有两个关键的接口LifecycleOwner 表示该类具有LifecycleLifecycleObserver** 监听生命周期事件** 以及 [LifecycleRegistry](https://developer.android.com/reference/androidx/lifecycle/LifecycleRegistry?hl=zh-cn) **将生命周期事件转发 ** 下面我们来自定义LifecycleOwner来实现Lifecycle的完整流转。

image.png

open class LActivity:Activity(),LifecycleOwner {

    /**
     * 负责转发生命周期事件
     */
    private var mFragmentLifecycleRegistry = LifecycleRegistry(this)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
    }

    override fun onStart() {
        super.onStart()
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
    }

    override fun onResume() {
        super.onResume()
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
    }

    override fun onStop() {
        super.onStop()
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
    }

    override fun onDestroy() {
        super.onDestroy()
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    }

    override fun getLifecycle(): Lifecycle {
        return mFragmentLifecycleRegistry
    }
}

LifecycleEventObserver监听生命周期:

class LifecycleActivity : LActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_lifecycle)
        //感知生命周期
        lifecycle.addObserver(MyLifecycleObserver())
    }
}

/**
 * 监听生命周期
 */
class MyLifecycleObserver:LifecycleEventObserver{
    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        Log.e("MyLifecycleObserver", "onStateChanged: ${source.lifecycle.currentState} event:${event}" )
    }
}

运行结果如下:Lifecycle的事件以及状态的对应关系
image.png

在Android的官方文档 给出的事件和状态的关系,如下图和我们上述的是一致的。 事件是监听生命周期的而状态是判断页面是否处于激活状态。

ON_CREATE 和 ON_STOP 对应着CREATED。ON_START和ON_PAUSE对应着STARTED。这样的状态对应是因为ON_PAUSE有重走onStart的潜力,而ON_STOP有重走onCreate的潜力

image.png

那么Lifecycle为什么要设计事件和状态呢?

Lifecycle事件和状态的对应关系

  • event:实现了 LifecycleObserver 的第三方组件,能够在 onCreateonDestroy 等 event 方法内完成对生命周期的监听,event 是针对 第三方组件内部作为观察者,来观察 页面对组件的推送。
  • state :的存在,主要是 为了方便使用者判断 页面是否处于激活状态,以便实现生命周期安全的通知,state 是针对 页面作为观察者,来观察 来自第三方组件内部对页面的推送,那么此时通过 state 的判断,我们可确保在页面处于非激活状态时不收到 基于 LifeCycle 的组件(比如 LiveData)的推送。

LiveData是根据State来判断生命周期是否处于活跃状态的,如下代码:

lifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)

只有 onResume 和 onPause 是介于 STARTED、RESUMED 状态之间,也即 只有这两个生命周期节点 100% 确定能收到 LiveData 的推送(FragmentActivity 额外支持 onStart 期间的接收)。

LifecycleRegistry 核心类

LifecycleRegistry 的设计如何去分发事件。其实看到源码可以和LiveData的分发消息差不多。

image.png

如下代码:通过handleLifecycleEvent发送生命周期事件

   // 分发生命周期事件 
   public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
        enforceMainThreadIfNeeded("handleLifecycleEvent");
        moveToState(event.getTargetState());
    }

    private void moveToState(State next) {
        ......
        sync();
        ......
    }
    
    private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        ....
        while (!isSynced()) {
            mNewEventOccurred = false;
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);
            }
            Map.Entry<LifecycleObserver, ObserverWithState> newest =
                mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);
            }
        }
        mNewEventOccurred = false;
    }

sync()方法分别调用了forwardPassbackwardPass进行分发生命周期事件。 监听生命周期事件及状态: mObserverMap 存储监听ObserverWithState

    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();

addObserver 添加监听事件,将obsever包装成ObserverWithState(这一段代码和LiveData中的observer类似)

    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        enforceMainThreadIfNeeded("addObserver");
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        //observer 包装ObserverWithState
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        //mObserverMap 存储statefulObserver
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

        //.......
        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        //重复addObserver 会返回之前的状态
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            final Event event = Event.upFrom(statefulObserver.mState);
            if (event == null) {
                throw new IllegalStateException("no event up from " + statefulObserver.mState);
            }
            //发送生命周期事件
            statefulObserver.dispatchEvent(lifecycleOwner, event);
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        mAddingObserverCounter--;
    }

ObserverWithState包装类通过dispatchEvent,在通过mLifecycleObserver.onStateChanged分发事件

    static class ObserverWithState {
        State mState;
        LifecycleEventObserver mLifecycleObserver;

        ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.lifecycleEventObserver(observer);
            mState = initialState;
        }

        void dispatchEvent(LifecycleOwner owner, Event event) {
            //获取该事件对应的状态
            State newState = event.getTargetState();
            //判断当前的状态
            mState = min(mState, newState);
            //发送事件及状态
            mLifecycleObserver.onStateChanged(owner, event);
            mState = newState;
        }
    }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容