Glide ,該功能非常強(qiáng)大 Android 圖片加載開源框架 相信大家并不陌生

創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供欒城網(wǎng)站建設(shè)、欒城做網(wǎng)站、欒城網(wǎng)站設(shè)計(jì)、欒城網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計(jì)與制作、欒城企業(yè)網(wǎng)站模板建站服務(wù),10年欒城做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
閱讀本文前,請務(wù)必先閱讀Glide的圖片加載功能源碼分析: Carson帶你學(xué)Android:圖片加載庫Glide源碼分析
該方法在圖片加載庫Glide加載圖片的源碼分析中曾進(jìn)行詳細(xì)說明,具體請看: Carson帶你學(xué)Android:圖片加載庫Glide源碼分析
至此,關(guān)于圖片加載庫的Gilde生命周期管理講解完畢。下面我將繼續(xù)對 Glide 的其他功能進(jìn)行源碼分析 ,有興趣可以繼續(xù)關(guān)注Carson帶你學(xué)Android開源庫系列文章:
不定期分享關(guān)于 安卓開發(fā) 的干貨,追求 短、平、快 ,但 卻不缺深度 。
簡單使用案例:
MainActivity:
MessageViewModel:
其中viewModel.getMessageObserver().observe(this, new Observer() )
中的this即SupportActivity :LifecycleOwner
SupportActivity implements LifecycleOwner
SupportActivity
SupportActivity就是通過getLifecycle()獲取 mLifecycleRegistry來標(biāo)記當(dāng)前Activity或Fragment的各種狀態(tài),其中ReportFragment.injectIfNeededIn(this)內(nèi)部源碼也是與mLifecycleRegistry.markState(Lifecycle.State.CREATED) 類似,狀態(tài)的信息記錄在mLifecycleRegistry對象內(nèi)部。Activity的其他類型的事件如onCreate,onPause等都是通過getLifecycle()獲取 mLifecycleRegistry對象調(diào)用mLifecycleRegistry內(nèi)部方法來改變其狀態(tài)的。
Fragment的狀態(tài)更加容易看到,F(xiàn)ragmentActivity即在Activity的生命周期中獲取
FragmentActivity部分源碼:
通過上面的簡單分析,兩個重要的類即 LifecycleRegistry extends Lifecycle:
下面是Lifecycle抽象類:
回到開始的案例:
LiveData.observe(this, new Observer);
這里我們傳入的Observer和 owner.getLifecycle().addObserver()即 Activity中的Lifecycle 是不同的。
我們上面已經(jīng)知道Activity中的Lifecycle是與生命周期相關(guān)的,通過Lifecycle.addObserver()可以監(jiān)聽到 Activity的生命周期 然后在LifecycleBoundObserver作出
相應(yīng)的處理,具體的實(shí)現(xiàn)在LifecycleRegistry.addObserver中(Lifecycle實(shí)現(xiàn)類),最終會根據(jù)事件變化調(diào)用 mLifecycleObserver.onStateChanged(owner, event),
LifecycleBoundObserver.onStateChanged - activeStateChanged - dispatchingValue - considerNotify(initiator) - observer.observer.onChanged((T) mData);
最終調(diào)用的是我們傳入的observer。
這樣看來 LiveDataT 就沒有什么特殊的了,把它看做一個普通的觀察者模式的管理者即可,比如EventBus。
看了幾天的Binder,決定有必要寫一篇博客,記錄一下學(xué)習(xí)成果,Binder是Android中比較綜合的一塊知識了,目前的理解只限于JAVA層。首先Binder是干嘛用的?不用說,跨進(jìn)程通信全靠它,操作系統(tǒng)的不同進(jìn)程之間,數(shù)據(jù)不共享,對于每個進(jìn)程來說,它都天真地以為自己獨(dú)享了整個系統(tǒng),完全不知道其他進(jìn)程的存在,進(jìn)程之間需要通信需要某種系統(tǒng)機(jī)制才能完成,在Android整個系統(tǒng)架構(gòu)中,采用了大量的C/S架構(gòu)的思想,所以Binder的作用就顯得非常重要了,但是這種機(jī)制為什么是Binder呢?在Linux中的RPC方式有管道,消息隊(duì)列,共享內(nèi)存等,消息隊(duì)列和管道采用存儲-轉(zhuǎn)發(fā)方式,即數(shù)據(jù)先從發(fā)送方緩存區(qū)拷貝到內(nèi)核開辟的緩存區(qū)中,然后再從內(nèi)核緩存區(qū)拷貝到接收方緩存區(qū),這樣就有兩次拷貝過程。共享內(nèi)存不需要拷貝,但控制復(fù)雜,難以使用。Binder是個折中的方案,只需要拷貝一次就行了。其次Binder的安全性比較好,好在哪里,在下還不是很清楚,基于安全性和傳輸?shù)男士紤],選擇了Binder。Binder的英文意思是粘結(jié)劑,Binder對象是一個可以跨進(jìn)程引用的對象,它的實(shí)體位于一個進(jìn)程中,這個進(jìn)程一般是Server端,該對象提供了一套方法用以實(shí)現(xiàn)對服務(wù)的請求,而它的引用卻遍布于系統(tǒng)的各個進(jìn)程(Client端)之中,這樣Client通過Binder的引用訪問Server,所以說,Binder就像膠水一樣,把系統(tǒng)各個進(jìn)程粘結(jié)在一起了,廢話確實(shí)有點(diǎn)多。
為了從而保障了系統(tǒng)的安全和穩(wěn)定,整個系統(tǒng)被劃分成內(nèi)核空間和用戶空間
內(nèi)核空間:獨(dú)立于普通的應(yīng)用程序,可以訪問受保護(hù)的內(nèi)存空間,有訪問底層硬件設(shè)備的所有權(quán)限。
用戶空間:相對與內(nèi)核空間,上層運(yùn)用程序所運(yùn)行的空間就是用戶空間,用戶空間訪問內(nèi)核空間的唯一方式就是系統(tǒng)調(diào)用。一個4G的虛擬地址空間,其中3G是用戶空間,剩余的1G是內(nèi)核空間。如果一個用戶空間想與另外一個用戶空間進(jìn)行通信,就需要內(nèi)核模塊支持,這個運(yùn)行在內(nèi)核空間的,負(fù)責(zé)各個用戶進(jìn)程通過Binder通信的內(nèi)核模塊叫做Binder驅(qū)動,雖然叫做Binder驅(qū)動,但是和硬件并沒有什么關(guān)系,只是實(shí)現(xiàn)方式和設(shè)備驅(qū)動程序是一樣的,提供了一些標(biāo)準(zhǔn)文件操作。
在寫AIDL的時候,一般情況下,我們有兩個進(jìn)程,一個作為Server端提供某種服務(wù),然后另外一個進(jìn)程作為Client端,連接Server端之后,就 可以使用Server里面定義的服務(wù)。這種思想是一種典型的C/S的思想。值得注意的是Android系統(tǒng)中的Binder自身也是C/S的架構(gòu),也有Server端與Client端。一個大的C/S架構(gòu)中,也有一個小的C/S架構(gòu)。
先籠統(tǒng)的說一下,在整個Binder框架中,由系列組件組成,分別是Client、Server、ServiceManager和Binder驅(qū)動程序,其中Client、Server和ServiceManager運(yùn)行在用戶空間,Binder驅(qū)動程序運(yùn)行內(nèi)核空間。運(yùn)行在用戶空間中的Client、Server和ServiceManager,是在三個不同進(jìn)程中的,Server進(jìn)程中中定義了服務(wù)提供給Client進(jìn)程使用,并且Server中有一個Binder實(shí)體,但是Server中定義的服務(wù)并不能直接被Client使用,它需要向ServiceManager注冊,然后Client要用服務(wù)的時候,直接向ServiceManager要,ServiceManager返回一個Binder的替身(引用)給Client,這樣Client就可以調(diào)用Server中的服務(wù)了。
場景 :進(jìn)程A要調(diào)用進(jìn)程B里面的一個draw方法處理圖片。
分析 :在這種場景下,進(jìn)程A作為Client端,進(jìn)程B做為Server端,但是A/B不在同一個進(jìn)程中,怎么來調(diào)用B進(jìn)程的draw方法呢,首先進(jìn)程B作為Server端創(chuàng)建了Binder實(shí)體,為其取一個字符形式,可讀易記的名字,并將這個Binder連同名字以數(shù)據(jù)包的形式通過Binder驅(qū)動發(fā)送給ServiceManager,也就是向ServiceManager注冊的過程,告訴ServiceManager,我是進(jìn)程B,擁有圖像處理的功能,ServiceManager從數(shù)據(jù)包中取出名字和引用以一個注冊表的形式保留了Server進(jìn)程的注冊信息。為什么是以數(shù)據(jù)包的形式呢,因?yàn)檫@是兩個進(jìn)程,直接傳遞對象是不行滴,只能是一些描述信息。現(xiàn)在Client端進(jìn)程A聯(lián)系ServiceManager,說現(xiàn)在我需要進(jìn)程B中圖像處理的功能,ServiceManager從注冊表中查到了這個Binder實(shí)體,但是呢,它并不是直接把這個Binder實(shí)體直接給Client,而是給了一個Binder實(shí)體的代理,或者說是引用,Client通過Binder的引用訪問Server。分析到現(xiàn)在,有個關(guān)鍵的問題需要說一下,ServiceManager是一個進(jìn)程,Server是另一個進(jìn)程,Server向ServiceManager注冊Binder必然會涉及進(jìn)程間通信。當(dāng)前實(shí)現(xiàn)的是進(jìn)程間通信卻又要用到進(jìn)程間通信,這就好象蛋可以孵出雞前提卻是要找只雞來孵蛋,確實(shí)是這樣的,ServiceManager中預(yù)先有了一個自己的Binder對象(實(shí)體),就是那只雞,然后Server有個Binder對象的引用,就是那個蛋,Server需要通過這個Binder的引用來實(shí)現(xiàn)Binder的注冊。雞就一只,蛋有很多,ServiceManager進(jìn)程的Binder對象(實(shí)體)僅有一個,其他進(jìn)程所擁有的全部都是它的代理。同樣一個Server端Binder實(shí)體也應(yīng)該只有一個,對應(yīng)所有Client端全部都是它的代理。
我們再次理解一下Binder是什么?在Binder通信模型的四個角色里面;他們的代表都是“Binder”,一個Binder對象就代表了所有,包括了Server,Client,ServiceManager,這樣,對于Binder通信的使用者而言,不用關(guān)心實(shí)現(xiàn)的細(xì)節(jié)。對Server來說,Binder指的是Binder實(shí)體,或者說是本地對象,對于Client來說,Binder指的是Binder代理對象,也就是Binder的引用。對于Binder驅(qū)動而言,在Binder對象進(jìn)行跨進(jìn)程傳遞的時候,Binder驅(qū)動會自動完成這兩種類型的轉(zhuǎn)換。
簡單的總結(jié)一下,通過上面一大段的分析,一個Server在使用的時候需要經(jīng)歷三個階段
1、定義一個AIDL文件
Game.aidl
GameManager .aidl
2、定義遠(yuǎn)端服務(wù)Service
在遠(yuǎn)程服務(wù)中的onBind方法,實(shí)現(xiàn)AIDL接口的具體方法,并且返回Binder對象
3、本地創(chuàng)建連接對象
以上就是一個遠(yuǎn)端服務(wù)的一般套路,如果是在兩個進(jìn)程中,就可以進(jìn)程通信了,現(xiàn)在我們分析一下,這個通信的流程。重點(diǎn)是GameManager這個編譯生成的類。
從類的關(guān)系來看,首先接口GameManager 繼承 IInterface ,IInterface是一個接口,在GameManager內(nèi)部有一個內(nèi)部類Stub,Stub繼承了Binder,(Binder實(shí)現(xiàn)了IBinder),并且實(shí)現(xiàn)了GameManager接口,在Stub中還有一個內(nèi)部類Proxy,Proxy也實(shí)現(xiàn)了GameManager接口,一個整體的結(jié)構(gòu)是這樣的
現(xiàn)在的問題是,Stub是什么?Proxy又是什么?在上面說了在Binder通信模型的四個角色里面;他們的代表都是“Binder”,一個Binder對象就代表了所有,包括了Server,Clinet,ServiceManager,為了兩個進(jìn)程的通信,系統(tǒng)給予的內(nèi)核支持是Binder,在抽象一點(diǎn)的說,Binder是系統(tǒng)開辟的一塊內(nèi)存空間,兩個進(jìn)程往這塊空間里面讀寫數(shù)據(jù)就行了,Stub從Binder中讀數(shù)據(jù),Proxy向Binder中寫數(shù)據(jù),達(dá)到進(jìn)程間通信的目的。首先我們分析Stub。
Stub 類繼承了Binder ,說明了Stub有了跨進(jìn)程傳輸?shù)哪芰Γ瑢?shí)現(xiàn)了GameManager接口,說明它有了根據(jù)游戲ID查詢一個游戲的能力。我們在bind一個Service之后,在onServiceConnecttion的回調(diào)里面,就是通過asInterface方法拿到一個遠(yuǎn)程的service的。
asInterface調(diào)用queryLocalInterface。
mDescriptor,mOwner其實(shí)是Binder的成員變量,Stub繼承了Binder,在構(gòu)造函數(shù)的時候,對著兩個變量賦的值。
如果客戶端和服務(wù)端是在一個進(jìn)程中,那么其實(shí)queryLocalInterface獲取的就是Stub對象,如果不在一個進(jìn)程queryLocalInterface查詢的對象肯定為null,因?yàn)椴煌M(jìn)程有不同虛擬機(jī),肯定查不到mOwner對象的,所以這時候其實(shí)是返回的Proxy對象了。拿到Stub對象后,通常在onServiceConnected中,就把這個對象轉(zhuǎn)換成我們多定義AIDL接口。
比如我們這里會轉(zhuǎn)換成GameManager,有了GameManager對象,就可以調(diào)用后querryGameById方法了。如果是一個進(jìn)程,那直接調(diào)用的是自己的querryGameById方法,如果不是一個進(jìn)程,那調(diào)用了就是代理的querryGameById方法了。
看到其中關(guān)鍵的一行是
mRemote就是一個IBinder對象,相對于Stub,Proxy 是組合關(guān)系(HAS-A),內(nèi)部有一個IBinder對象mRemote,Stub是繼承關(guān)系(IS-A),直接實(shí)現(xiàn)了IBinder接口。
transact是個native方法,最終還會回掉JAVA層的onTransact方法。
onTransact根據(jù)調(diào)用號(每個AIDL函數(shù)都有一個編號,在跨進(jìn)程的時候,不會傳遞函數(shù),而是傳遞編號指明調(diào)用哪個函數(shù))調(diào)用相關(guān)函數(shù);在這個例子里面,調(diào)用了Binder本地對象的querryGameById方法;這個方法將結(jié)果返回給驅(qū)動,驅(qū)動喚醒掛起的Client進(jìn)程里面的線程并將結(jié)果返回。于是一次跨進(jìn)程調(diào)用就完成了。
***Please accept mybest wishes for your happiness and success ! ***
一、問題:在Android啟動后會在新進(jìn)程里創(chuàng)建一個主線程,也叫UI線程( 非線程安全 )這個線程主要負(fù)責(zé)監(jiān)聽屏幕點(diǎn)擊事件與界面繪制。當(dāng)Application需要進(jìn)行耗時操作如網(wǎng)絡(luò)請求等,如直接在主線程進(jìn)行容易發(fā)生ANR錯誤。所以會創(chuàng)建子線程來執(zhí)行耗時任務(wù),當(dāng)子線程執(zhí)行完畢需要通知UI線程并修改界面時,不可以直接在子線程修改UI,怎么辦?
解決方法:Message Queue機(jī)制可以實(shí)現(xiàn)子線程與UI線程的通信。
該機(jī)制包括Handler、Message Queue、Looper。Handler可以把消息/ Runnable對象 發(fā)給Looper,由它把消息放入所屬線程的消息隊(duì)列中,然后Looper又會自動把消息隊(duì)列里的消息/Runnable對象 廣播 到所屬線程里的Handler,由Handler處理接收到的消息或Runnable對象。
1、Handler
每次創(chuàng)建Handler對象時,它會自動綁定到創(chuàng)建它的線程上。如果是主線程則默認(rèn)包含一個Message Queue,否則需要自己創(chuàng)建一個消息隊(duì)列來存儲。
Handler是多個線程通信的信使。比如在線程A中創(chuàng)建AHandler,給它綁定一個ALooper,同時創(chuàng)建屬于A的消息隊(duì)列AMessageQueue。然后在線程B中使用AHandler發(fā)送消息給ALooper,ALooper會把消息存入到AMessageQueue,然后再把AMessageQueue廣播給A線程里的AHandler,它接收到消息會進(jìn)行處理。從而實(shí)現(xiàn)通信。
2、Message Queue
在主線程里默認(rèn)包含了一個消息隊(duì)列不需要手動創(chuàng)建。在子線程里,使用Looper.prepare()方法后,會先檢查子線程是否已有一個looper對象,如果有則無法創(chuàng)建,因?yàn)槊總€線程只能擁有一個消息隊(duì)列。沒有的話就為子線程創(chuàng)建一個消息隊(duì)列。
Handler類包含Looper指針和MessageQueue指針,而Looper里包含實(shí)際MessageQueue與當(dāng)前線程指針。
下面分別就UI線程和worker線程講解handler創(chuàng)建過程:
首先,創(chuàng)建handler時,會自動檢查當(dāng)前線程是否包含looper對象,如果包含,則將handler內(nèi)的消息隊(duì)列指向looper內(nèi)部的消息隊(duì)列,否則,拋出異常請求執(zhí)行l(wèi)ooper.prepare()方法。
- 在 UI線程 中,系統(tǒng)自動創(chuàng)建了Looper 對象,所以,直接new一個handler即可使用該機(jī)制;
- 在 worker線程 中,如果直接創(chuàng)建handler會拋出運(yùn)行時異常-即通過查‘線程-value’映射表發(fā)現(xiàn)當(dāng)前線程無looper對象。所以需要先調(diào)用Looper.prepare()方法。在prepare方法里,利用ThreadLocalLooper對象為當(dāng)前線程創(chuàng)建一個Looper(利用了一個Values類,即一個Map映射表,專為thread存儲value,此處為當(dāng)前thread存儲一個looper對象)。然后繼續(xù)創(chuàng)建handler, 讓handler內(nèi)部的消息隊(duì)列指向該looper的消息隊(duì)列(這個很重要,讓handler指向looper里的消息隊(duì)列,即二者共享同一個消息隊(duì)列,然后handler向這個消息隊(duì)列發(fā)送消息,looper從這個消息隊(duì)列獲取消息) 。然后looper循環(huán)消息隊(duì)列即可。當(dāng)獲取到message消息,會找出message對象里的target,即原始發(fā)送handler,從而回調(diào)handler的handleMessage() 方法進(jìn)行處理。
- handler與looper共享消息隊(duì)列 ,所以handler發(fā)送消息只要入列,looper直接取消息即可。
- 線程與looper映射表 :一個線程最多可以映射一個looper對象。通過查表可知當(dāng)前線程是否包含looper,如果已經(jīng)包含則不再創(chuàng)建新looper。
5、基于這樣的機(jī)制是怎樣實(shí)現(xiàn)線程隔離的,即在線程中通信呢。?
核心在于 每一個線程擁有自己的handler、message queue、looper體系 。而 每個線程的Handler是公開 的。B線程可以調(diào)用A線程的handler發(fā)送消息到A的共享消息隊(duì)列去,然后A的looper會自動從共享消息隊(duì)列取出消息進(jìn)行處理。反之一樣。
二、上面是基于子線程中利用主線程提供的Handler發(fā)送消息出去,然后主線程的Looper從消息隊(duì)列中獲取并處理。那么還有另外兩種情況:
1、主線程發(fā)送消息到子線程中;
采用的方法和前面類似。要在子線程中實(shí)例化AHandler并設(shè)定處理消息的方法,同時由于子線程沒有消息隊(duì)列和Looper的輪詢,所以要加上Looper.prepare(),Looper.loop()分別創(chuàng)建消息隊(duì)列和開啟輪詢。然后在主線程中使用該AHandler去發(fā)送消息即可。
2、子線程A與子線程B之間的通信。
1、 Handler為什么能夠?qū)崿F(xiàn)不同線程的通信?核心點(diǎn)在哪?
不同線程之間,每個線程擁有自己的Handler、消息隊(duì)列和Looper。Handler是公共的,線程可以通過使用目標(biāo)線程的Handler對象來發(fā)送消息,這個消息會自動發(fā)送到所屬線程的消息隊(duì)列中去,線程自帶的Looper對象會不斷循環(huán)從里面取出消息并把消息發(fā)送給Handler,回調(diào)自身Handler的handlerMessage方法,從而實(shí)現(xiàn)了消息的線程間傳遞。
2、 Handler的核心是一種事件激活式(類似傳遞一個中斷)的還是主要是用于傳遞大量數(shù)據(jù)的?重點(diǎn)在Message的內(nèi)容,偏向于數(shù)據(jù)傳輸還是事件傳輸。
目前的理解,它所依賴的是消息隊(duì)列,發(fā)送的自然是消息,即類似事件中斷。
0、 Android消息處理機(jī)制(Handler、Looper、MessageQueue與Message)
1、 Handler、Looper源碼閱讀
2、 Android異步消息處理機(jī)制完全解析,帶你從源碼的角度徹底理解
謝謝!
wingjay

Android RecyclerView繪制頁面的源碼分析一
Android RecyclerView布局管理器LinearLayoutManager源碼分析二
以上兩篇講述了RecycerView LinearLayoutManager 頁面繪制以及子條目的布局,LinearLayoutManager 是一個線性的管理器即是控制垂直以及水平展示 一個條目表示一行,然而顯示生活中有很多需求是一行展示多個子條目這個時候就用到了 GridLayoutManager 表格布局管理器 來實(shí)現(xiàn)這種需求
GridLayoutManager :繼承于LinearLayoutManager的網(wǎng)格狀布局管理器 默認(rèn)一行展示一個
GridLayoutManager網(wǎng)格布局管理器 實(shí)現(xiàn)一行展示多個條目,本章解釋了GridLayoutManager的簡單源碼實(shí)現(xiàn)表格布局的大概調(diào)用,下一章展示復(fù)雜的表格布局即展示不顧地條目數(shù)的表格布局
您可能聽說過View ,ViewManager,Window,PhoneWindow,WindowManager,WindowManagerService,可是你知道這幾個類是什么關(guān)系,干嘛用的。概括的來說,View是放在Window中的,Window是一個抽象類,它的具體實(shí)現(xiàn)是PhoneWindow,PhoneWindow還有個內(nèi)部類DecorView,WindowManager是一個interface,繼承自ViewManager,它是外界訪問Window的入口,,提供了add/remove/updata的方法操作View,WindowManager與WindowManagerSerice是個跨進(jìn)程的過程,WindowManagerService的職責(zé)是對系統(tǒng)中的所有窗口進(jìn)行管理。如果您不太清楚,建議往下看,否則就不要看了。
Android系統(tǒng)的Window有很多種,大體上來說,F(xiàn)ramework定義了三種窗口類型;
這就是Framework定義了三種窗口類型,這三種類型定義在WindowManager的內(nèi)部類LayoutParams中,WindowManager講這三種類型 進(jìn)行了細(xì)化,把每一種類型都用一個int常量來表示,這些常量代表窗口所在的層,WindowManagerService在進(jìn)行窗口疊加的時候,會按照常量的大小分配不同的層,常量值越大,代表位置越靠上面, 所以我們可以猜想一下,應(yīng)用程序Window的層值常量要小于子Window的層值常量,子Window的層值常量要小于系統(tǒng)Window的層值常量。 Window的層級關(guān)系如下所示。
上面說了Window分為三種,用Window的type區(qū)分,在搞清楚Window的創(chuàng)建之前,我們需要知道怎么去描述一個Window,我們就把Window當(dāng)做一個實(shí)體類,給我的感覺,它必須要下面幾個字段。
實(shí)際上WindowManager.LayoutParams對Window有很詳細(xì)的定義。
提取幾個重要的參數(shù)
Window是一個是一個抽象的概念,千萬不要認(rèn)為我們所看到的就是Window,我們平時所看到的是視圖,每一個Window都對應(yīng)著一個View,View和Window通過ViewRootImpl來建立聯(lián)系。有了View,Window的存在意義在哪里呢,因?yàn)閂iew不能單獨(dú)存在,它必須依附著Window,所以有視圖的地方就有Window,比如Activity,一個Dialog,一個PopWindow,一個菜單,一個Toast等等。
通過上面我們知道視圖和Window的關(guān)系,那么有一個問題,是先有視圖,還是先有Window。這個答案只有在源碼中找了。應(yīng)用程序的入口類是ActivityThread,在ActivityThread中有performLaunchActivity來啟動Activity,這個performLaunchActivity方法內(nèi)部會創(chuàng)建一個Activity。
如果activity不為null,就會調(diào)用attach,在attach方法中通過PolicyManager創(chuàng)建了Window對象,并且給Window設(shè)置了回調(diào)接口。
PolicyManager的實(shí)現(xiàn)類是Policy
這樣Window就創(chuàng)建出來了, 所以先有Window,后有視圖,視圖依賴Window存在 ,再說一說視圖(Activity)為Window設(shè)置的回調(diào)接口。
Activity實(shí)現(xiàn)了這個回調(diào)接口,當(dāng)Window的狀態(tài)發(fā)生變化的時候,就會回調(diào)Activity中實(shí)現(xiàn)的這些接口,有些回調(diào)接口我們還是熟悉的,dispatchTouchEvent,onAttachedToWindow,onDetachedFromWindow等。
下面分析view是如何附屬到window上的,通過上面可以看到,在attach之后就要執(zhí)行callActivityOnCreate,在onCreate中我們會調(diào)用setContentView方法。
getWindow獲取了Window對象,Window的具體實(shí)現(xiàn)類是PhoneWindow,所以要看PhoneWindow的setContentView方法。
這里涉及到一個mContentParent變量,他是一個DecorView的一部分,DecorView是PhoneWindow的一個內(nèi)部類,我先介紹一下關(guān)于DecorView的知識。
DecorView是Activity的頂級VIew,DecorView繼承自FrameLayout,在DecorView中有上下兩個部分,上面是標(biāo)題欄,下面是內(nèi)容欄,我們通過PhoneWindow的setContentView所設(shè)置的布局文件是加到內(nèi)容欄(mContentParent)里面的,View層的事件都是先經(jīng)過DecorView在傳遞給我們的View的。
OK在回到setContentView的源碼分析,我們可以得到Activity的Window創(chuàng)建需要三步。
- 1、 如果沒有DecorView,在installDecor中創(chuàng)建DecorView。
- 2、將View添加到decorview中的mContentParent中。
- 3、回調(diào)Activity的onContentChanged接口。
先看看第一步,installDecor的源碼
installDecor中調(diào)用了generateDecor,繼續(xù)看
直接給new一個DecorView,有了DecorView之后,就可以加載具體的布局文件到DecorView中了,具體的布局文件和系統(tǒng)和主題有關(guān)系。
在看第二步,將View添加到decorview中的mContentParent中。
直接將Activity視圖加到DecorView的mContentParent中,最后一步,回調(diào)Activity的onContentChanged接口。在Activity中尋找onContentChanged方法,它是個空實(shí)現(xiàn),我們可以在子Activity中處理。
到此DecorView被創(chuàng)建完畢,我們一開始從Thread中的handleLaunchActivity方法開始分析,首先加載Activity的字節(jié)碼文件,利用反射的方式創(chuàng)建一個Activity對象,調(diào)用Activity對象的attach方法,在attach方法中,創(chuàng)建系統(tǒng)需要的Window并為設(shè)置回調(diào),這個回調(diào)定義在Window之中,由Activity實(shí)現(xiàn),當(dāng)Window的狀態(tài)發(fā)生變化的時候,就會回調(diào)Activity實(shí)現(xiàn)的這些回調(diào)方法。調(diào)用attach方法之后,Window被創(chuàng)建完成,這時候需要關(guān)聯(lián)我們的視圖,在handleLaunchActivity中的attach執(zhí)行之后就要執(zhí)行handleLaunchActivity中的callActivityOnCreate,在onCreate中我們會調(diào)用setContentView方法。通過setContentView,創(chuàng)建了Activity的頂級View---DecorView,DecorView的內(nèi)容欄(mContentParent)用來顯示我們的布局。 這個是我們上面分析得到了一個大致流程,走到這里,這只是添加的過程,還要有一個顯示的過程,顯示的過程就要調(diào)用handleLaunchActivity中的handleResumeActivity方法了。最后會調(diào)用makeVisible方法。
這里面首先拿到WindowManager對象,用tWindowManager 的父接口ViewManager接收,ViewManager可以
最后調(diào)用 mDecor.setVisibility(View.VISIBLE)設(shè)置mDecor可見。到此,我們終于明白一個Activity是怎么顯示在我們的面前了。
參考鏈接:
網(wǎng)站名稱:android源碼分析,android webview源碼分析
URL地址:http://chinadenli.net/article32/dsgcgsc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、網(wǎng)站設(shè)計(jì)公司、網(wǎng)站策劃、做網(wǎng)站、小程序開發(fā)、手機(jī)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)