Android Architecture Components 之Lifecycle-Aware 的源碼及trick

一 背景

google的Architecture Components Components(lz 簡寫AAC)出來好久了鸟整,但一直沒時間閱讀源碼京髓,趁最近空擋洒缀,閱讀了AAC的源碼跷坝,分享下閱讀的理解倦蚪。

二 AAC是個什么東西

其實,AAC就是google提出的一種app開發(fā)框架痢法,里面最基礎(chǔ)的應(yīng)該就是Lifecycle-Aware了狱窘。 在這之前,我們組開發(fā)采用的mvvm + data binding 模式疯暑。 這個模式中训柴,我們常常這樣一個需求哑舒, 我們需要在fragment onDestroy 或 onPause時妇拯,反注冊ViewModel中釋放資源, 需要層層經(jīng)過洗鸵, ViewModel -- > adapter--> fragment ViewModel ——> fragment等幾級回調(diào)越锈。而Lifecycle-Aware 這時就有一個優(yōu)勢,就是跟生命周期綁定膘滨, 直接在相應(yīng)生命周期邏輯處理好就好甘凭。當(dāng)然,這里也是一種解耦方式火邓,采用觀察者模式實現(xiàn)丹弱。

三 Lifecycle-Aware 的源碼

觀察者模式

a 首先找使用入口, 一般我們是這樣使用Lifecycle-Aware的铲咨,
Lifecycle lifecycle = lifecycleOwner.getLifecycle();
        lifecycle.addObserver((GenericLifecycleObserver) (source, event) -> {
           
        });
b lifecycle的addObserver方法躲胳,如下:
@Override
    public void addObserver(LifecycleObserver observer) {
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

      //已添加
        if (previous != null) {
            return;
        }

       //第二次重入
        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;

        State targetState = calculateTargetState(observer);
        mAddingObserverCounter++;
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            pushParentState(statefulObserver.mState);
            statefulObserver.dispatchEvent(mLifecycleOwner, upEvent(statefulObserver.mState));
            popParentState();
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }

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

statefulObserver.dispatchEvent(mLifecycleOwner, upEvent(statefulObserver.mState))一句就會調(diào)用 mLifecycleObserver.onStateChanged(owner, event);即我們上述入口的GenericLifecycleObserver的 void onStateChanged(LifecycleOwner source, Lifecycle.Event event)方法。

c 特別說明下纤勒,ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
 ObserverWithState(LifecycleObserver observer, State initialState) {
            mLifecycleObserver = Lifecycling.getCallback(observer);
            mState = initialState;
        }
d 包裝Observer為 GenericLifecycleObserver坯苹。 這里我們注意到,使用了反射摇天。 同事在使用時粹湃,遇到一個bug就是正式包會crash, 原因就是此版本的混淆文件沒對Lifecycling類進(jìn)行keep泉坐。
static GenericLifecycleObserver getCallback(Object object) {
        if (object instanceof GenericLifecycleObserver) {
            return (GenericLifecycleObserver) object;
        }
        //noinspection TryWithIdenticalCatches
        try {
            final Class<?> klass = object.getClass();
            Constructor<? extends GenericLifecycleObserver> cachedConstructor = sCallbackCache.get(
                    klass);
            if (cachedConstructor != null) {
                return cachedConstructor.newInstance(object);
            }
            cachedConstructor = getGeneratedAdapterConstructor(klass);
            if (cachedConstructor != null) {
                if (!cachedConstructor.isAccessible()) {
                    cachedConstructor.setAccessible(true);
                }
            } else {
                cachedConstructor = sREFLECTIVE;
            }
            sCallbackCache.put(klass, cachedConstructor);
            return cachedConstructor.newInstance(object);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }
e 另外为鳄, sync()方法如下:
// happens only on the top of stack (never in reentrance),
    // so it doesn't have to take in account parents
    private void sync() {
        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();
            }
            Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
            if (!mNewEventOccurred && newest != null
                    && mState.compareTo(newest.getValue().mState) > 0) {
                forwardPass();
            }
        }
        mNewEventOccurred = false;
    }
f 如果處于初始化周期,onResume及以前forwardPass()腕让,正向回調(diào)之前的生命周期嫌松。 onPause及以后, 逆向回調(diào)backwardPass()枝冀。

這時,特別數(shù)據(jù)結(jié)構(gòu)FastSafeIterableMap就比較優(yōu)勢构捡,支持正逆向遍歷。 如果當(dāng)前狀態(tài)小于以前狀態(tài)壳猜, 正向回調(diào)勾徽, 否則逆向回調(diào)。這里處理與fragment生命周期狀態(tài)類似统扳。狀態(tài)機(jī)喘帚,貼一下官方盜圖:

image.png

trick 1 無ui fragment 綁定命周期

a 目前Android sdk 26.1.0 已支持了 Lifecycle-Aware。 我們先選取Activity 來看咒钟。Lifecycle-Aware的 初始化邏輯在SupportActivity 吹由, BaseFragmentActivityApi14 extends SupportActivity,可以看出最低版本是sdk 14 朱嘴, 最后繼承的是我們最熟悉的子類是FragmentActivity extends BaseFragmentActivityApi16倾鲫。
image.png
b 這里是整個AAC常見的套路, 使用無ui fragment來同步activity的生命周期萍嬉。具體ReportFragment inject的代碼如下乌昔。
 public static void injectIfNeededIn(Activity activity) {
        // ProcessLifecycleOwner should always correctly work and some activities may not extend
        // FragmentActivity from support lib, so we use framework fragments for activities
        android.app.FragmentManager manager = activity.getFragmentManager();
        if (manager.findFragmentByTag(REPORT_FRAGMENT_TAG) == null) {
            manager.beginTransaction().add(new ReportFragment(), REPORT_FRAGMENT_TAG).commit();
            // Hopefully, we are the first to make a transaction.
            manager.executePendingTransactions();
        }
    }
c 代碼比較簡單在create等回調(diào),dispatch對應(yīng)的事件壤追。
 @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        dispatchCreate(mProcessListener);
        dispatch(Lifecycle.Event.ON_CREATE);
    }

給對應(yīng)實現(xiàn)了的LifecycleRegistryOwner或LifecycleOwner activity回調(diào)

private void dispatch(Lifecycle.Event event) {
        Activity activity = getActivity();
        if (activity instanceof LifecycleRegistryOwner) {
            ((LifecycleRegistryOwner) activity).getLifecycle().handleLifecycleEvent(event);
            return;
        }

        if (activity instanceof LifecycleOwner) {
            Lifecycle lifecycle = ((LifecycleOwner) activity).getLifecycle();
            if (lifecycle instanceof LifecycleRegistry) {
                ((LifecycleRegistry) lifecycle).handleLifecycleEvent(event);
            }
        }
    }
 public void handleLifecycleEvent(Lifecycle.Event event) {
        mState = getStateAfter(event);
        if (mHandlingEvent || mAddingObserverCounter != 0) {
            mNewEventOccurred = true;
            // we will figure out what to do on upper level.
            return;
        }
        mHandlingEvent = true;
        sync();
        mHandlingEvent = false;
    }

這時會去同步一遍狀態(tài)

sample trick 2

另外一個小的點是磕道,在BaseSample中使用ContentProvider onCreate中綁定activity和fragment生命周期,這點就不詳述了行冰。

public class ProcessLifecycleOwnerInitializer extends ContentProvider {
    @Override
    public boolean onCreate() {
        LifecycleDispatcher.init(getContext());
        ProcessLifecycleOwner.init(getContext());
        return true;
    } 
  溺蕉。。悼做。
}
image.png

繼續(xù)盜圖疯特,左邊部分就是目前的回調(diào)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贿堰,一起剝皮案震驚了整個濱河市辙芍,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌羹与,老刑警劉巖故硅,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異纵搁,居然都是意外死亡吃衅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門腾誉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來徘层,“玉大人峻呕,你說我怎么就攤上這事∪ばВ” “怎么了瘦癌?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長跷敬。 經(jīng)常有香客問我讯私,道長,這世上最難降的妖魔是什么西傀? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任斤寇,我火速辦了婚禮,結(jié)果婚禮上拥褂,老公的妹妹穿的比我還像新娘娘锁。我一直安慰自己,他們只是感情好饺鹃,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布莫秆。 她就那樣靜靜地躺著,像睡著了一般尤慰。 火紅的嫁衣襯著肌膚如雪馏锡。 梳的紋絲不亂的頭發(fā)上雷蹂,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天伟端,我揣著相機(jī)與錄音,去河邊找鬼匪煌。 笑死责蝠,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萎庭。 我是一名探鬼主播霜医,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼驳规!你這毒婦竟也來了肴敛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤吗购,失蹤者是張志新(化名)和其女友劉穎医男,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捻勉,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡镀梭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了踱启。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片报账。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡研底,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出透罢,到底是詐尸還是另有隱情榜晦,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布羽圃,位于F島的核電站芽隆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏统屈。R本人自食惡果不足惜胚吁,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望愁憔。 院中可真熱鬧腕扶,春花似錦、人聲如沸吨掌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽膜宋。三九已至窿侈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間秋茫,已是汗流浹背史简。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留肛著,地道東北人圆兵。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像枢贿,于是被迫代替她去往敵國和親殉农。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

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