Android LifeCycle 使用以及應(yīng)用分析

在我最近編寫的項(xiàng)目中癌蚁,始終貫穿整個(gè)事件流的組件,可能就是LifeCycle了戳寸,在我眼里呈驶,它就像是個(gè)通用化的UI生命周期管理對(duì)象,在Android View層的生命周期方法被調(diào)用時(shí)疫鹊,它可以給所有注冊(cè)過(guò)它的方法發(fā)送生命周期事件袖瞻,然后由你決定是否進(jìn)行處理。

那么問(wèn)題來(lái)了拆吆,這不就是接口+觀察者模式就可以實(shí)現(xiàn)么虏辫?那樣它看起來(lái)并不像它本身那么酷啊。

話不多說(shuō)锈拨,先上使用場(chǎng)景

例子1 來(lái)自我們經(jīng)典的sunflower

// GalleryFragment.kt   
private fun search(query: String) {
    // Make sure we cancel the previous job before creating a new one
    searchJob?.cancel()
    searchJob = lifecycleScope.launch {  // 這里可以看成是綁定了View生命周期的線程,一旦View生命停止羹唠,它也將被釋放
        viewModel.searchPictures(query).collectLatest {   // 執(zhí)行的任務(wù)
            adapter.submitData(it)
        }
    }
}

可能你會(huì)特別蒙蔽奕枢,不急娄昆,我們直接 進(jìn)入lifecycleScope中看看

// LifecycleOwner.kt
val LifecycleOwner.lifecycleScope: LifecycleCoroutineScope get() = lifecycle.coroutineScope
// 上面又是kotlin無(wú)比裝逼的寫法 但是可以看出來(lái) 返回的是LifecycleCoroutineScope

// Lifecycle.kt
val Lifecycle.coroutineScope: LifecycleCoroutineScope  // ok 返回的就是我了
    get() {
        while (true) {
            val existing = mInternalScopeRef.get() as LifecycleCoroutineScopeImpl?  
            if (existing != null) {
                return existing
            }
            val newScope = LifecycleCoroutineScopeImpl(    // 如果沒(méi)有這個(gè)任務(wù) 就新建任務(wù)
                this,
                SupervisorJob() + Dispatchers.Main.immediate
            )
            if (mInternalScopeRef.compareAndSet(null, newScope)) {   // 這個(gè)方法 CAS 蕪湖, 把新加的注冊(cè)進(jìn)列表
                newScope.register()
                return newScope
            }
        }
    }

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@NonNull
AtomicReference<Object> mInternalScopeRef = new AtomicReference<>(); // 看到這個(gè)Java老哥不會(huì)陌生了把缝彬,CAS原子操作 看到它就會(huì)不自然的想到unsafe =萌焰。= (老面試哥的職業(yè)病)

internal class LifecycleCoroutineScopeImpl(  //  由我來(lái)實(shí)現(xiàn) 協(xié)程(還是想吐槽谷浅,攜程是不是給了kotlin廣告費(fèi))+ View的生命周期綁定
    override val lifecycle: Lifecycle,
    override val coroutineContext: CoroutineContext
) : LifecycleCoroutineScope(), LifecycleEventObserver {
    init {
        // in case we are initialized on a non-main thread, make a best effort check before
        // we return the scope. This is not sync but if developer is launching on a non-main
        // dispatcher, they cannot be 100% sure anyways.
        if (lifecycle.currentState == Lifecycle.State.DESTROYED) { // 生命周期被銷毀
            coroutineContext.cancel() // 協(xié)程取消 
        }
    }

    fun register() {
        launch(Dispatchers.Main.immediate) {
            if (lifecycle.currentState >= Lifecycle.State.INITIALIZED) {
                lifecycle.addObserver(this@LifecycleCoroutineScopeImpl)
            } else {
                coroutineContext.cancel()
            }
        }
    }

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        if (lifecycle.currentState <= Lifecycle.State.DESTROYED) {
            lifecycle.removeObserver(this)
            coroutineContext.cancel()
        }
    }
}

上面就是LifeCycle在協(xié)程生命周期上的管理體現(xiàn)(google你為什么不早不做扒俯,想起了當(dāng)年被生命周期支配的恐懼)

例子2:來(lái)自自己的項(xiàng)目

首先要說(shuō)明一下,Android在RxJava + RxAndroid的使用中一疯,內(nèi)存泄漏是很常見的問(wèn)題撼玄,因?yàn)楫惒饺蝿?wù)本身是不會(huì)去感知你View的生命周期的,我自己項(xiàng)目中使用的是autoDispose

三方框架實(shí)現(xiàn)了RxJava墩邀、RxAndroid任務(wù)對(duì)LifeCycle的綁定

// 登錄請(qǐng)求
RxView.clicks(mDataBinding.loginBtn)
        .subscribeOn(AndroidSchedulers.mainThread())
        .to(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this))) // 沒(méi)錯(cuò)就是我 我綁定了LifecycleOwner
        .subscribe(unit ->
                PermissionTools.requestPermission(this, () ->             //                       校驗(yàn)讀寫權(quán)限
                                mViewModel.Login(mDataBinding.userNameEdt.getText().toString().trim()  //  登錄請(qǐng)求
                                        , mDataBinding.passwordEdt.getText().toString().trim())
                        , Permission.READ_PHONE_STATE));

 // 登錄信息返回通知
LiveEventBus.get(RequestTags.LOGIN_REQ, BaseResponBean.class)
        .observe(this, bean -> {  // 我也綁定了LifecycleOwner
            Optional.ofNullable(mLoading).ifPresent(builder -> mLoading.getObj().dismiss());  // 取消 Loading
                if (bean.getCode() == 200) { // 登錄成功
                    ToastUtil.showToast(LoginActivity.this, "登錄成功掌猛!");
                    startActivity(new Intent(LoginActivity.this, MainActivity.class));
                    finish();
                } else {                     // 登錄失敗
                    ToastUtil.showToast(LoginActivity.this, "登錄失敗:" + TCErrorConstants.getErrorInfo(bean.getCode()));
                    mDataBinding.passwordEdt.setText("");  // 清空密碼輸入框
                }
        });

以上就是兩個(gè)十分簡(jiǎn)單的LifeCycle的實(shí)際運(yùn)用,下面分析一下LifeCycle到底做了些什么眉睹。

我們通過(guò)AppCompatActivity找到他的父類荔茬,F(xiàn)ragmentActivity的父類, ComponentActivity

//LifecycleOwner.java
public interface LifecycleOwner {
    /**
     * Returns the Lifecycle of the provider.
     *
     * @return The lifecycle of the provider.
     */
    @NonNull
    Lifecycle getLifecycle();
}

//ComponentActivity.java
public class ComponentActivity extends androidx.core.app.ComponentActivity implements
        LifecycleOwner,
        ViewModelStoreOwner,
        SavedStateRegistryOwner,
        OnBackPressedDispatcherOwner {
            
    private final LifecycleRegistry mLifecycleRegistry = new LifecycleRegistry(this);   
            
    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return mLifecycleRegistry;  // 我返回的就是LifeCycle
    }        
    ......       
}

//LifecycleRegistry.java 這算是核心類了
public class LifecycleRegistry extends Lifecycle {
    //FastSafeIterableMap 它最重要的特點(diǎn)就是竹海,支持在遍歷的過(guò)程中刪除任意元素慕蔚,不會(huì)觸發(fā)ConcurrentModifiedException
    //自然 它也無(wú)法保證線程安全 這個(gè)對(duì)象是以模擬Map的形式,存了訂閱者key斋配,以及訂閱者的狀態(tài)value
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();
    
    //你可以泄漏我Lifecycle 但是你沒(méi)法泄漏LifecycleOwner 
    private final WeakReference<LifecycleOwner> mLifecycleOwner; 

    /**
     * Current state
     */
    private State mState; // 這個(gè)就不用說(shuō)了吧
    
    // 更新狀態(tài)
    @MainThread
    public void setCurrentState(@NonNull State state) {
        moveToState(state);
    }
    
    // 開始更新
    private void moveToState(State next) {
        if (mState == next) { // 重復(fù)事件 丟棄
            return;
        }
        mState = next; // 本地事件狀態(tài)更新
        if (mHandlingEvent || mAddingObserverCounter != 0) {  // 如果上一次同步?jīng)]有進(jìn)行完 或 表示正在同步新訂閱者的數(shù)量為0 就不處理了
            mNewEventOccurred = true;
            // we will figure out what to do on upper level.
            return;
        }
        mHandlingEvent = true;    // 開始同步
        sync();
        mHandlingEvent = false;   // 同步結(jié)束
    }    
    
    // 同步所有觀察者
    private void sync() {
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            throw new IllegalStateException("LifecycleOwner of this LifecycleRegistry is already"
                    + "garbage collected. It is too late to change lifecycle state.");
        }
        while (!isSynced()) {
            mNewEventOccurred = false;
            // no need to check eldest for nullability, because isSynced does it for us.
            if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
                backwardPass(lifecycleOwner);  // 每次同步只向低等級(jí)移動(dòng)
            }
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass(lifecycleOwner);  // 每次同步向高等級(jí)移動(dòng)
            }
        }
        mNewEventOccurred = false;
    }
    
    // 判斷是否以及全部同步完成
    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;
    }    
}

lifecycle.PNG

看圖說(shuō)話 backwardPass 就是RESUMED 到 DESTROYED 的過(guò)程孔飒,每次只能變化一次,連續(xù)的動(dòng)作

forwardPass就是INITIALIZED 到 RESUMED 的過(guò)程许起,同樣 每次只能變化一次十偶, 連續(xù)的動(dòng)作

這時(shí)候問(wèn)題就來(lái)了,為什么要這么做园细? 而且那個(gè)嵌套的判斷如何解決在同步的過(guò)程中有新的觀察者加入的情況

這是可以細(xì)化成兩個(gè)小點(diǎn)

在同步過(guò)程中惦积,加入了新觀察者

在同步過(guò)程中,新狀態(tài)更變加入

private void forwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> ascendingIterator =
            mObserverMap.iteratorWithAdditions();
    while (ascendingIterator.hasNext() && !mNewEventOccurred) {  // 中斷機(jī)制猛频,如果有新的狀態(tài)更變或是訂閱者出現(xiàn)狮崩,上一次同步會(huì)被中斷
        Entry<LifecycleObserver, ObserverWithState> entry = ascendingIterator.next();
        ObserverWithState observer = entry.getValue();
        while ((observer.mState.compareTo(mState) < 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) { 
            pushParentState(observer.mState);   // 入棧
            observer.dispatchEvent(lifecycleOwner, upEvent(observer.mState)); // 回調(diào)通知狀態(tài)更變
            popParentState(); // 出棧
        }
    }
}

private void backwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
    while (descendingIterator.hasNext() && !mNewEventOccurred) {// 中斷機(jī)制,如果有新的狀態(tài)更變或是訂閱者出現(xiàn)鹿寻,上一次同步會(huì)被中斷
        Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
        ObserverWithState observer = entry.getValue();
        while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            Event event = downEvent(observer.mState);
            pushParentState(getStateAfter(event));
            observer.dispatchEvent(lifecycleOwner, event);
            popParentState();
        }
    }
}

這里又出現(xiàn)了個(gè)pushParentState以及popParentState 這個(gè)棧又是為了保證什么的呢

為了保證新增的狀態(tài)不會(huì)破壞整個(gè)Map的有序性

這時(shí)候你會(huì)覺得奇怪睦柴,有序性?什么有序性

仔細(xì)看一下sync就會(huì)明白毡熏,同步的判斷依賴于新加入的訂閱者狀態(tài)肯定新于之前加入的訂閱者

private State calculateTargetState(LifecycleObserver observer) {
    Entry<LifecycleObserver, ObserverWithState> previous = mObserverMap.ceil(observer);
    //previous代表訂閱者的當(dāng)前狀態(tài)
    State siblingState = previous != null ? previous.getValue().mState : null;
    //在出現(xiàn)事件嵌套時(shí)坦敌,棧內(nèi)不為空,最后加入的那個(gè)狀態(tài),肯定是最新的狀態(tài)
    State parentState = !mParentStates.isEmpty() ? mParentStates.get(mParentStates.size() - 1)
            : null;
    //mParentStates狱窘,它限制了新的訂閱者的狀態(tài)更新晚于前面的訂閱者
    return min(min(mState, siblingState), parentState);
}

這應(yīng)該算是犧牲一部分性能保證有序性的操作

以上就是Lifecycle一次狀態(tài)更變的大致流程杜顺,看起來(lái)確實(shí)也沒(méi)有太多東西,一個(gè)觀察者模式蘸炸,一套新規(guī)則躬络,解決了長(zhǎng)年的生命周期管理問(wèn)題,看來(lái)基于業(yè)務(wù)的開發(fā)才是未來(lái)的主流

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搭儒,一起剝皮案震驚了整個(gè)濱河市穷当,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淹禾,老刑警劉巖馁菜,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異稀拐,居然都是意外死亡火邓,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門德撬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)铲咨,“玉大人,你說(shuō)我怎么就攤上這事蜓洪∠死眨” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵隆檀,是天一觀的道長(zhǎng)摇天。 經(jīng)常有香客問(wèn)我,道長(zhǎng)恐仑,這世上最難降的妖魔是什么泉坐? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮裳仆,結(jié)果婚禮上腕让,老公的妹妹穿的比我還像新娘。我一直安慰自己歧斟,他們只是感情好纯丸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著静袖,像睡著了一般觉鼻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上队橙,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天坠陈,我揣著相機(jī)與錄音萨惑,去河邊找鬼。 笑死仇矾,一個(gè)胖子當(dāng)著我的面吹牛咒钟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播若未,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼倾鲫!你這毒婦竟也來(lái)了粗合?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤乌昔,失蹤者是張志新(化名)和其女友劉穎隙疚,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磕道,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡供屉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了溺蕉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伶丐。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖疯特,靈堂內(nèi)的尸體忽然破棺而出哗魂,到底是詐尸還是另有隱情,我是刑警寧澤漓雅,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布录别,位于F島的核電站,受9級(jí)特大地震影響邻吞,放射性物質(zhì)發(fā)生泄漏组题。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一抱冷、第九天 我趴在偏房一處隱蔽的房頂上張望崔列。 院中可真熱鬧,春花似錦徘层、人聲如沸峻呕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瘦癌。三九已至,卻和暖如春跷敬,著一層夾襖步出監(jiān)牢的瞬間讯私,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留斤寇,地道東北人桶癣。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像娘锁,于是被迫代替她去往敵國(guó)和親牙寞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容