由于安卓已經誕生快二十載,其最初的開發思想與現代的開發思想已經大相徑庭,特別是Jetpack庫誕生之后,項目中存在著新老思想混雜的情況,讓許多的新手老手都措手不及,項目大步向屎山邁進。為了解決這個問題,開發者必須弄懂新舊兩種開發模式,這就是《安卓現代化開發系列》誕生的意義,本系列并不會包含隱晦難懂的代碼,一切的文字都是以理解本質為主,起到一個拋鉆引玉的作用。
生命周期的前世今生
1.1、前世——初識篇
天地初開,一切皆為混沌的時代,安卓宇宙中誕生了名為Activity
(活動)的組件,Activity
是Android應用中最關鍵的組件,一個Activity
通常對應的是App的一個頁面,當手機使用者在不同的頁面之間導航的時候,新的Activity
會誕生,同時也會在特定的時候銷毀。一個頁面的誕生之初到它銷毀的這段時間,名為「生命周期」。
理解并掌握生命周期是每一個Android修煉者的必修功力,因為生命周期的每一個階段均代表Activity
處于不同的狀態之中,一旦錯誤處理生命周期周期,修煉者輕則內傷殘疾(手機耗電過多,丟失信息),重則走火入魔(程序崩潰)。
關于生命周期,江湖中一直流傳著一張「Activity生命周期總覽圖」,但個中奧秘,卻鮮為人知,因此少有人能夠修煉到最高境界:
由圖可見,Activity
的生命周期中,提供了6種回調:onCreate()
、onStart()
、onResume()
、onPause()
、onStop()
、onDestroy()
,需要特別注意的是,這僅僅是一種回調,與我們通常的認識不同都是,生命周期的某個階段是指一個時間段 ,而回調或者說事件只是一個瞬間,換句話來說,onCreate并不是指生命周期中存在一個階段名為onCreate,而是Activity
觸發了onCreate事件,即將進入已創建階段。
然而可惜的是,在遠古Android的設計中,Android的創世神并沒有為開發者提供具體的生命周期階段的概念,僅僅是提供了進入某個生命周期階段的回調,因此上述提到的“已創建”這個狀態在原生安卓的概念中并不存在。然而在后人的努力中,生命周期階段這一概念最終得到確定與落實,不過這都是后話了。
1.2、前世——詳解篇
1.2.1、onCreate()、onDestroy()
- onCreate() :
Activity
生命周期的起點,首次被系統創建時觸發,整個生命周期只會觸發一次。此回調通常用于執行頁面View的設置,例如setContentView()
。 - onDestroy() :
Activity
生命周期的終點,在Activity
被銷毀前觸發,此回調的有兩種情況被調用:
- 用戶手動關閉
Activity
(按返回鍵)或者系統主動關閉Activity
(一般是App進程因內存不足被銷毀,導致Activity
也被銷毀)。 - 配置變更(設備旋轉、語言切換等)。
簡單來說,onCreate()是Activity
被創建的時刻,onDestroy()是Activity
即將被銷毀的時刻。
一個Activity
進入onDestroy() 之后,理應被GC回收,但是如果此時它仍然被引用(例如被某些網絡請求的回調中被引用),那么此Activity
就會導致內存泄漏 ,這也是所有Android開發者需要關注其生命周期的原因。
1.2.2、onStart()、onStop()
- onStart() :當
Activity
在onCreate()之后不久就會觸發此回調,說明了Activity
此刻進入了“已開始”的狀態,但是此刻的Activity
仍然未獲取焦點。
很多Android開發者一直搞不懂Activity為什么會存在一個可見但是沒有獲取焦點的狀態,會存在這種疑惑的原因是因為Android通常作為一種移動設備的系統而存在,而移動設備由于其特殊性,通常也只會同屏存在一個頁面,因此可見但是沒有獲取焦點這種狀態幾乎只存在一瞬間(它馬上就會遮住之前正在交互的頁面),然而我們以電腦系統的角度來看,電腦系統的桌面上基本都是多窗口并存的,然而即使存在了多窗口,用戶能交互的也僅僅只有獲取焦點的那個窗口。
因此,可見但是沒有獲取焦點的窗口,就像是電腦上那些打開著、但被用戶正在交互的窗口擋住的那些窗口,假如電腦桌面上存在著一個QQ窗口,然而用戶正在編寫一個Word文檔,那么被Word擋住的那個QQ窗口,就是可見但未獲取焦點的窗口。
- onStop() :當一個
Activity
從可見但是沒有獲取到焦點的狀態變為完全不可見的狀態時就會觸發此回調,按照上文類比,這種情況通常可以理解為:電腦桌面上的一個被遮擋的窗口被最小化了。
1.2.3、onResume()、onPause()
- onResume() :當
Activity
從可見但是沒有獲取焦點的狀態變成可見同時獲取焦點的狀態時,觸發此回調,同樣按照電腦系統的角度來理解,這種情況通常可以理解為:電腦桌面上的一個被遮擋的窗口此刻被用戶交互了。 - onPause() :當
Activity
從“可見同時獲取焦點”的狀態變成可見但是沒有獲取焦點的狀態時,觸發此回調,同樣同樣按照電腦系統的角度來理解,這種情況通常可以理解為:電腦桌面上的一個正在被用戶交互的窗口,由于用戶操作了其他窗口,導致當前的窗口被遮擋了,也因此失去了焦點。
1.3、前世——總結篇
我們從電腦系統的窗口去理解Activity
的生命周期:
- 啟動一個程序的時候,程序就會在電腦桌面上創建一個窗口,創建的那一瞬間(通常會很快,可能不需要1秒)就相當于
Activity
的onCreate()。 - 創建完成后,窗口就可以被用戶所看見了,被用戶看到的那一瞬間就相當于
Activity
的onStart()。 - 通常來說,一個新啟動的程序會自動獲得焦點并可被用戶交互,因此onStart()之后,窗口會被置頂到頂層,這一瞬間就相當于
Activity
的onResume()。 - 當用戶選擇其他窗口時,之前交互的窗口并不會消失,而是會失去焦點并被用戶最新交互的窗口所遮擋,這一瞬間就相當于
Activity
的onPause()。 - 當用戶最小化窗口時,窗口就會進入后臺(并不是銷毀)而且并不能被用戶所看見,這一瞬間就相當于進入了
Activity
的onStop()。 - 當用戶關閉程序亦或者電腦內存不足時,程序被銷毀,窗口同時也被銷毀了,這一瞬間就相當于進入了
Activity
的onDestroy()。
一個窗口當然可以失去焦點后重新獲取焦點,因此onPause()和onResume()可能在生命周期中多次被執行,同理窗口也可以最小化之后重新最大化,onStart()和onStop()也可能在生命周期中多次被執行。只不過對于移動設備來說,幾乎不存在頁面失去焦點后又重新獲得焦點的情況,因為移動設備的頁面絕大多數情況都是一個頁面可被用戶交互,被擋住的頁面完全不可見,即等價于電腦系統中只存在一個最大化的頁面,所以移動設備的Activity
的生命周期通常只會在onStart()和onStop()兩者之間流轉(當然,仍然會遵循onStart()->onResumt()->onPause()->onStop()的順序)。
而一個窗口只能被創建和銷毀一次,因此在Activity
的生命周期中,onCreate()和onDestroy()只會被調用一次。
上文中提到,原生的Android生命周期設計中,只提供了進入某個生命周期狀態的回調,并沒有提供具體的狀態的定義,例如onCreate() 與onStart()之間的狀態叫什么呢,官方的文檔提到了這個叫“已創建”的狀態,然而這只存在于文本性的文檔中,這在代碼中并不存在,只能作為一種“共識”的定義。這也為開發者之間溝通生命周期帶來了極大的困擾。
2.1、今生——初識篇
經歷漫長的混沌時代之后,Jetpack攜帶著「Lifecycle」正式進入到了Android的世界中,「Lifecycle」為千千萬萬的Android修煉者帶來了福音,因為它比起傳統的基于回調的方式來感知生命周期的方式有以下的優點:
- 提出了「生命周期狀態」的概念,彌補了安卓傳統的生命周期只有事件沒有狀態的缺陷
- 將生命周期管理從頁面(如Activity和Fragment)脫離,將生命周期監聽的職責轉移到組件中,降低頁面與組件的耦合度。
為了讓讀者更加清晰使用「Lifecycle」與不使用它之間的區別,這里使用兩個代碼案例來對比:
- 首先,定義一個常見的基于回調的監聽類,每秒鐘會對外廣播一次字符串。
- 在
Activity
中的onCreate()階段初始化監聽,然后在onStart()中開啟監聽,在onStop()中關閉監聽,這樣的好處是當頁面不可見的時候不會浪費手機性能。
以上便是傳統安卓開發中最直接也是最常見的一種根據生命周期來實現監聽的方式,讓我們分析一下這種方式的缺點:
- 真實業務開發中,同一頁面中往往存在大量的生命周期監聽需求,
Activity
等生命周期組件會同時管理大量的組件,讓代碼難以維護。 - 代碼缺乏一致性,需要監聽生命周期的組件存在許多模板代碼。試想一下,一個需要在onStart()啟動,在onStop()關閉的、同時在項目中大量存在的組件,某天需要它在onResume()做一些操作,那將會導致災難,因為需要每一處使用它的代碼中增加onResume()的修改,一旦遺漏這個修改將會導致不可預知的bug。
- 無法獲取實時的生命周期狀態。假設在onStart()的階段,需要執行一個網絡請求或者其他耗時操作之后再調用
listener.start()
的場景下,無法保證此刻頁面仍然處于可見的狀態,開發者也無法獲取「當前所處狀態」來避免不可見的時候仍然調用listener.start()
(這個缺陷上文已經提到,原生安卓生命周期只提供了生命周期事件而沒有生命周期狀態)。
讓我們看一看使用了「Lifecycle」庫之后的生命周期是如何實現監聽的:
我們讓需要監聽Activity
生命周期的MyListener
組件實現DefaultLifecycleObserver
接口,然后重寫onStart()、onStop()方法,然后直接在Activity
中獲取lifecycle
然后調用其addObserver()
即可。
我們會發現,「生命周期管理」的責任從Activity
轉移到了組件中,Activity
本身只負責對外廣播自身的生命周期,這樣極大減少了Activity
的維護負擔。
2.2、今生——詳解篇
2.2.1、Lifecycle(opens new window)
Lifecycle包含兩個定義,一個指的是Jetpack庫中的Lifecycle組件庫,一個指的是Lifecycle組件庫中的一個核心類,后文中如果沒有特指情況下,文章中描述的默認為類
上文中提到,安卓原生中只有描述生命周期的事件,缺乏一種描述當前生命周期所處的狀態,但是「Lifecycle」庫中補全了狀態,下圖中闡述了事件與狀態的關系:
根據「Lifecycle」庫的定義,一個生命周期狀態的起點是「Initialized」,終點是「Destroyed」,當發生生命周期事件時,生命周期狀態就會發生移動,包括狀態提升和狀態下降。
我們把狀態從Initialized到Resumed當做一個從小到大的狀態,如果狀態值變小了,則稱為狀態下降,反之則為狀態提升。
初步的定義有了,讓我們把視角聚焦于Lifecycle
類的源碼:
可以看到,Lifecycle
類的設計基本遵循生命周期事件與狀態圖例,一個Lifecycle
只有2個核心功能:
- 緩存當前的生命周期狀態(currentState)。
- 添加與移除生命周期觀察者。
上述代碼中,對Event
和State
的部分代碼進行了省略,下面展開講解:
首先是Event
類,Event
類對應的是生命周期事件,也就是原生安卓生命周期的事件,即onCreate()、onPause()等。
該類提供了一個targetState
的屬性,指的是發生了該事件之后,生命周期狀態發生改變的狀態目標。
例如發生了ON_CREATE事件,這是狀態從「Initialized」向「Created」轉移的瞬間,那么targetState自然就是「State.CREATED」了;同理發生ON_STOP事件時,是狀態從「Started」向「Created」轉移的瞬間,targetState也是「State.CREATED」。
此處不必死記硬背,只需要配合狀態與事件圖理解其意義即可。
該類還提供了四個方法,downFrom()、downTo()、upFrom()、upTo(),這些都是當狀態發生提升或者降級的時候,方便獲取對應的事件的便捷方法,以downFrom()舉例:
downFrom(state:State)的含義是獲取會導致state發生狀態下降的事件,假如State.Created,發生什么事件會導致狀態從State.Created下降呢,我們回去查看狀態與事件圖,發現是發生了ON_DESTROY事件,那么該方法就會返回ON_DESTROY。
此處不必死記硬背,只需要配合狀態與事件圖理解其意義即可。
看完了Event,我們把視角轉向State:
State
的代碼非常簡單甚至不用一絲的省略,除了枚舉值外僅有一個方法:isAtLeast(state:State) ,此方法的含義是用于判斷當前的狀態是否大于或等于目標值的狀態。
如何理解呢?還記得上文提到的嗎,狀態是有大小的:
我們把狀態從Initialized到Resumed當做一個從小到大的狀態,如果狀態值變小了,則稱為狀態下降,反之則為狀態提升。
因此對于生命周期的狀態而言,Created是比Initialized大的,isAtLeast(state:State)
的含義就是判斷生命周期是否比某個預期值“走的更遠”了,如果一個行為可以在組件創建后被執行,那么換句話說,只要生命周期的狀態大于或者等于Created即可。
上文中提到,原生的生命周期回調無法實時獲取生命周期所處的狀態,一旦在生命周期回調方法中執行一些耗時操作,就無法耗時操作結束后,仍處于安全的生命周期區間,例如下面的代碼:
我們嘗試在onStart()中執行一段耗時操作再開啟監聽,但是執行耗時操作期間無法Activity
是否已經處于onStop()了,此刻我們就可以使用isAtLeast(state:State)
來判斷耗時操作結束后的生命周期狀態:
可見,「Lifecycle」庫確實解決了生命周期只有事件沒有狀態的問題,開發者可以輕易獲取當前的生命周期所處的階段。
2.2.2、LifecycleOwner(opens new window)
首先,我們看看它的源碼:
非常的簡單,只是給實現者對外提供一個獲取Lifecycle
的入口,為什么要這樣設計呢?還記得Lifecycle
嗎,它并不是一個接口而是一個抽象類,在Jvm中是單繼承的,因此不太可能會讓帶有生命周期的組件直接繼承Lifecycle
抽象類。
因此在實際使用中,帶有生命周期的組件和Lifecycle
是包含的關系,即下圖的情況:
為什么谷歌的開發人員要如此奇怪呢,讓
Lifecycle
變成接口,讓Activity實現接口不一樣能讓組件訪問到Lifecycle
嗎?先別急,Lifecycle
的具體實現我們還沒看,等到那一節將會解答這個疑問。
總結:LifecycleOwner
只是一個簡單的對外提供訪問Lifecycle
的接口。
2.2.3、LifecycleObserver(opens new window)
此處就不放代碼了,因為這是一個空接口,作用是將其實現者變成一個生命周期的觀察者。
其本身不起作用,業務中我們通常使用其子接口,例如DefaultLifecycleObserver
、LifecycleEventObserver
等,可以回去查看2.1節的MyListener
實現了DefaultLifecycleObserver
之后是如何感知Activity
的生命周期的。
2.2.4、LifecycleRegistry(opens new window)
此類是「Lifecycle」庫的核心類,也是Lifecycle
抽象類的直接實現,它的作用是管理生命周期事件的派發,但是其做了非常多的優化,例如解決了產生事件時,迭代觀察者過程中可能會新增或者移除觀察者,用ArrayList遍歷會崩的問題、新加入的觀察者如何派發事件的問題,移除觀察者如何更新狀態的問題等等。
這些谷歌的開發人員都幫我們解決了,只需要按下圖簡單配置一下即可使用:
可見,我們只需要按照上文提到的結構,在Activity
中實例化一個LifecycleRegistry
,然后在合適的生命周期回調中派發響應的事件,所有監聽當前Activity
生命周期的組件就可以獲取到當前Activity
的生命周期了。
需要注意的是:上述代碼僅僅是為了為你展示Lifecycle
是如何實現生命周期事件派發的,實際使用中,并不需要為Activity
手動派發事件,ComponentActivity
、AppcompatActivity
實際上已經配置好了派發邏輯,開發中直接獲取Lifecycle
即可。
下面即將深入LifecycleRegistry
的源碼層面探究一下它的原理,但是需要注意的是,本文章的目的并不是讓讀者100%搞懂源碼中每一行代碼的運行邏輯,因為這違背了本系列文章的初衷——讓讀者能夠在對庫有足夠充足的了解下開發,同時筆者也沒有100%搞懂源碼每一行的邏輯。
如果讀者非常有鉆研精神,可以看一下這個博主的文章,他對LifecycleRegistry
的源碼做了非常詳細的講解:
下面我們看看LifecycleRegistry的代碼脈絡:
筆者省去了絕大部分和業務無關的代碼,只保留了最核心最精華的代碼,其實被移除掉的代碼都是為了解決前文中提到的“遍歷過程中增刪列表”、”新加入的觀察者如何派發事件“等細枝末節的問題,與本文主題關系不大。
可以看到,LifecycleRegistry
本質上就是一個強化版的觀察者模式的設計,添加觀察者(observer)、遍歷派發事件的模式。
還記得上文提到的一個小問題嗎,為什么LifecycleOwner
不直接設計成接口而是以成員變量的方式掛載在對應的生命周期組件里面呢?通過LifecycleRegistry
的源碼我們可以看到,LifecycleOwner
被以弱引用的方式存放著的,也就是說處理生命周期事件派發的LifecycleRegistry
并不會直接引用LifecycleOwner
,可以認為是谷歌的開發人員是為了防止產生內存泄漏而故意設計的。
2.2.5、小總結
我們已經依次瀏覽了「Lifecycle」庫中的四個最核心的組件,他們的關系如果你已經搞混了,筆者再次通過一段極簡的代碼的方式來強化讀者對他們的理解:
關于四個核心組件的總結:
Lifecycle
描述的是存放和管理生命周期的容器LifecycleRegistry
是Lifecycle
的實現類LifecycleObserver
是觀察生命周期變化的監聽器LifecycleOwner
是對外提供Lifecycle
的提供者。
3、谷歌眼中的Lifecycle
3.1、ComponentActivity
此類是谷歌官方基于Activity開發的子類,其集成了許多Jetpack庫的核心功能,其中就包括了「Lifecycle」庫,該類因此也實現了LifecycleOwner
接口,開發者常用的AppcompatActvity
也是該類的子類。
但是細讀源碼會發現,該類并沒有像筆者之前展示的源碼那樣,直接調用LifecycleRegistry
在特定的Activity
生命周期回調中派發事件,那么該類是如何實現生命周期事件的派發的呢?下面介紹「Lifecycle」庫中的另外一個關鍵類:ReportFragment。
3.1.1、ReportFragment與LifecycleCallbacks
在ComponentActivity
的onCreate()中,有一段ReportFragment.injectIfNeededIn(this)
的代碼,這個就是實現了生命周期事件派發的核心類。
接下來讓我們走進ReportFragment
的源碼,正如前文所述,文章并不會闡述每一行代碼的原理,而是抓住主要的脈絡,隱藏了和主脈絡無關的代碼,但是剩余的代碼量仍然挺多,讀者不必對大量的代碼感到恐慌,因為文章會逐一解釋:
可見,ReportFragment
做的事非常簡單,就是在其生命周期的各個階段上報生命周期事件,因為Fragment
的生命周期和Activity
在絕大部分是保持一致的(特殊的如onCreate()
除外,不過也有onActivityCreated()
、onActivityPostCreated()
等可以感知Activity
生命周期的函數),谷歌的開發人員于是就利用ReportFragment
作為監聽Activity
生命周期的工具,你可以看到這個Fragment是沒有UI的,這也間接證明了它的任務并不是展示一個UI而僅僅是為了監聽生命周期。
讓我們回到injectIfNeedIn() ,可以清楚的看到這里做了一個版本判斷,如果大于api版本大于29,則使用LifecycleCallbacks
做一個注冊的邏輯,這是怎么回事呢?
在我提到ReportFragment
是作為一個生命周期監聽者而不是一個展示UI的模塊的時候,你也許就已經隱隱約約聞到一種非常奇怪的味道。由于安卓源碼設計的缺陷(只對外提供了回調方法而沒有提供回調監聽注冊),開發者對待這一問題必須考慮向下兼容,因此他們選擇了源碼中已經存在的、可以監聽Activity
的生命周期的Fragment
,但是在api 29之后,Activity原生自帶了生命周期的回調監聽注冊,因此一旦檢測到api大于或者等于29,ReportFragment
的作用就形同虛設了,因為廣播生命周期的事件的任務已經轉移給Activity
自帶的生命周期回調來實現了。
你也許還會擔心,現在有ReportFragment
和Activity
自帶的生命周期回調兩種方式了,會不會導致一個事件被廣播兩次呢?其實不用擔心,廣播的時候已經做了排除了,只有api小于29的情況下,ReportFragment
才會生效。
3.2、Fragment
Fragment
本身的生命周期和Activity
沒有很大的差異,依然是內置LifecycleRegistry
然后在合適的生命周期回調中廣播生命周期事件的一套,但是值得注意的是:
當
Fragment
被FragmentManager
管理時,例如執行replace()
事務中,邏輯上當前的Fragment
只是被另外一個同類所替換了,它并沒有真的被銷毀(因為待會還有重新回來的機會),因此該Fragment
并不會執行onDestroy()
,然而由于內存上的考量,不可見的Fragment
的View
理應被回收,因此View
會被銷毀。換句話說,
Fragment
不可見之后,它的狀態會保存起來,但是其View
會被銷毀,待會再次可見的時候,會根據其狀態再一次執行onCreateView() 。
上述機制導致了一個問題:Fragment
的生命周期和其對應的View
的生命周期在實質上是不對等的,然而實際開發中感知生命周期大多數是為了與UI進行互動,這也導致了開發者單純監聽Fragment
的生命周期已經不能夠滿足開發上的需求了。
下面這張來源于谷歌官方開發者文檔的圖片很好的詮釋了Fragment
和它的View
的生命周期關系:
假如一個Fragment
正在棧頂,他會處于Resumed的階段,但是被replace之后,它會進入Created階段,此刻View
被銷毀,View
會進入Destroyed階段,但是Fragment
重回棧頂的時候,Fragment
會從Created再次回歸到Resume,而View
會從Destroyed重回Resumed狀態。
換句話說,在Fragment
的生命周期中,它的View可能會反復的從Destroyed到Resumed之間移動(即不斷地銷毀與創建)
谷歌為了緩解這個問題,給Fragment
的View
單獨添加了一套生命周期,我們可以通過代碼看到端倪:
可以看到,在Fragment
執行performCreateView()
的時候,會初始化View
的Lifecycle,兩者的生命周期事件是單獨通知的。
- 如果開發者想訪問
Fragment
的生命周期,在Fragment
中訪問lifecycleOwner
即可。 - 如果開發者想訪問
Fragment
的View
的生命周期,在Fragment
中訪問viewLifecycleOwner
即可。
3.3、ViewTreeLifecycleOwner
在上述的代碼中,能夠直接訪問Activity
、Fragment
的Lifecycle的只能是它們的類中,而很多需要訪問生命周期的地方往往是一些View
中,例如要在View
中監聽其父組件生命周期,然而View
的父控件有非常多,包括了Activity
、Fragment
甚至是Dialog
乃至更多,要想獲取父組件的生命周期,只能做類型判斷+類型強轉的工作,這樣就極大的限制了View
的使用范圍:
為了緩解,谷歌的開發人員提出了一種叫ViewTreeLifecycleOwner
的設計,其實這個東西并沒有什么神秘的,讓我們直接看看源碼:
通篇只有兩個View
的擴展函數,第一個函數的意義是給對應的View
綁上一個LifecycleOwner
,第二個函數的意義是不斷往上查找父控件,直到查出之前綁定的LifecycleOwner
。
這段源碼的作用挺簡單的,也就是說只要給某個頂層的控件提前綁好了LifecycleOwner
,那么他下轄的所有子View
都可以通過往上查找的方式來找到LifecycleOwner
,不得不說谷歌的開發人員真的是太厲害了,在簡陋的基礎下做出了非常強大的功能。
那么下面的問題是:LifecycleOwner
的綁定發生在哪里呢?
3.3.1、Activity中的綁定
? Activity的直接子類ComponentActivity
、AppcompatActivity
均自動完成了綁定的工作,我們以ComponentActivity
為例看看相關的綁定代碼:
可見在ComponentActivity
的setContentView
被執行時,會將Activity
的ViewLifecycleOwner
綁定其所在的Window
的DecorView
中,我們都知道Activity
下面的所有View
都是DecorView
的子View,因此它們都可以直接通過谷歌開發人員提供的擴展函數直接訪問到最頂層的Activity
的Lifecycle
。
3.3.2、Fragment中的綁定
和Activity
類似,Fragment
也采用了幾乎一致的綁定方式,只不過是將Lifecycle
綁定在了Fragment
的View
之上:
3.3.3、Dialog中的綁定
默認的Dialog
和Activity
是不支持ViewTreeLifecycleOwner
的,因此谷歌的開發人員重新繼承實現了一個新的Dialog子類:ComponentDialog
,其中的綁定大同小異,簡單看下源碼即可了解:
看來和Activity
一樣,把LifecycleOwner
綁定在了DecorView
中。
3.3.4、意義與總結
那么谷歌的開發人員費盡心思的為以上的組件綁定ViewTreeLifecycleOwner
有何用意呢?意義可大了,由于消除了組件之間的差異(均是通過View
往上查找父控件直到找到LifecycleOwner
的模式),我們不用在乎當前的View
是在哪個控件中,都是統一通過findViewTreeLifecycleOwner()
來獲取最頂層控件的生命周期。
例如下面的自定義View的代碼,無論在上述哪個控件中都可以用:
可見,開發者只需要關注生命周期本身,不再需要擔心不同組件之間的差異了。
4、結語
安卓原生的生命周期設計只能說是毛坯房都算不上的水平,然而通過「Lifecycle」庫的加持之后,開發者可以輕松訪問組件的生命周期,讓開發業務更加的合理與安全。
作為開發者的你,應該逐漸將重寫生命周期函數的方式逐漸過渡到「Lifecycle」的開發方式中來,在一些工具類亦或者其他業務類中,你也可以使用「Lifecycle」輔助強化與生命周期相關的業務。
Android 學習筆錄
Jetpack全家桶篇(內含Compose):https://qr18.cn/A0gajp
Android 性能優化篇:https://qr18.cn/FVlo89
Android Framework底層原理篇:https://qr18.cn/AQpN4J
Android 車載篇:https://qr18.cn/F05ZCM
Android 逆向安全學習筆記:https://qr18.cn/CQ5TcL
Android 音視頻篇:https://qr18.cn/Ei3VPD
OkHttp 源碼解析筆記:https://qr18.cn/Cw0pBD
Gradle 篇:https://qr18.cn/DzrmMB
Kotlin 篇:https://qr18.cn/CdjtAF
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知識體:https://qr18.cn/CyxarU
Android 核心筆記:https://qr21.cn/CaZQLo
Android 往年面試題錦:https://qr18.cn/CKV8OZ
2023年最新Android 面試題集:https://qr18.cn/CgxrRy
Android 車載開發崗位面試習題:https://qr18.cn/FTlyCJ
音視頻面試題錦:https://qr18.cn/AcV6Ap