摘要:最近有好多人問我沒信心去深造了,找不到好的工作,其實(shí)我以一個(gè)他們進(jìn)行回復(fù),發(fā)現(xiàn)他們主要是內(nèi)心比較浮躁,要知道技術(shù)行業(yè)永遠(yuǎn)缺少的是高手。至此整體繪制過程我們就已經(jīng)非常清楚了。我門可以根據(jù)這種繪制的流程來操作自己的自定義組件。
最近有好多人問我Android沒信心去深造了,找不到好的工作,其實(shí)我以一個(gè)他們進(jìn)行回復(fù),發(fā)現(xiàn)他們主要是內(nèi)心比較浮躁,要知道技術(shù)行業(yè)永遠(yuǎn)缺少的是高手。建議先閱讀淺談Android發(fā)展趨勢分析,在工作中,總結(jié)菜式王道,沉淀才能成長!
前言在android當(dāng)中對于UI體系當(dāng)中往往我們會在繪制UI的時(shí)候碰到各種各樣的問題而不知道從何解決, 也有時(shí)需要開發(fā)更改自定義組件時(shí),需要做自己的調(diào)整,或者是實(shí)現(xiàn)某個(gè)自定義特效時(shí)的思路不明確,想要達(dá)到去玩轉(zhuǎn)UI的最為基礎(chǔ)的部分,就是去全面的深入了解UI的繪制流程.所以接下來帶大家去進(jìn)行全面分析UI整體的繪制體系.
思路:android程序啟動--->Activity加載并完成生命周期--->setContentView--->圖形繪制
疑惑:1.Android程序是如何啟動,Activity生命周期如何調(diào)用?
2.在Activity onCreate當(dāng)中我們的setContentView是如何將UI文件加載?
3.UI是如何繪制的?答案:
眾所周知,我們的java程序想要開啟需要依賴于main方法,也就是我們的程序入口(主線程)進(jìn)入,但是在我們?nèi)粘i_發(fā)android程序的過程當(dāng)中我們并沒有發(fā)現(xiàn)main方法的存在,那么android當(dāng)中的是如何開始運(yùn)行的?
熟悉的朋友們可能都知道在android當(dāng)中存在一個(gè)叫做ActivityThread的類,這個(gè)類代表的是android當(dāng)中的主線程,而在這個(gè)類當(dāng)中我們看到了比較熟悉的main方法,那么現(xiàn)在是否可以認(rèn)為我們的android在打開app時(shí)是首先調(diào)用的是當(dāng)前這個(gè)類的main,也就是此處為我們的啟動點(diǎn)
在此處可以看到Activity調(diào)用了一個(gè)attach()方法
在這里我們可能首先要考慮的是getService拿出來的是什么?
進(jìn)去之后,我們會發(fā)現(xiàn)
在這個(gè)當(dāng)中,里面調(diào)用了的系統(tǒng)的ActivityManagerService這個(gè)服務(wù),并且給出了一個(gè)Binder接口
那么在這里,我們可以聯(lián)想到,在android當(dāng)中的binder通信機(jī)制,那么實(shí)際上我們的ActivityManager是有系統(tǒng)服務(wù)所調(diào)用管理,并且通過在binder接口當(dāng)中進(jìn)行調(diào)用,這也是為什么我們講Activity是跨進(jìn)程訪問的原因
那么明白了這個(gè)時(shí)候能夠得到ActivityManager之后,我們接著回到attach當(dāng)中繼續(xù)看下去, 這個(gè)時(shí)候會發(fā)現(xiàn),我們調(diào)用了一個(gè)attachApplication方法(見圖2)這個(gè)方法又是干嘛的?attachApplication在這里的作用其實(shí)實(shí)際上是ActivityThread通過attach獲取到,然后將applciationThread將其關(guān)聯(lián),把a(bǔ)ctivity相關(guān)信息存儲在applciationThread里面,apllicationThread的類為activity的各種狀態(tài)做了相對應(yīng)的準(zhǔn)備工作
這個(gè)時(shí)候我們需要關(guān)注,ApplicationThread當(dāng)中做了什么?
當(dāng)我們打開ApplicationThread中我們會看到一堆的schedle方法,這些方法的名稱其實(shí)就可以給我們表明,代表的是在執(zhí)行Activity的某種狀態(tài)時(shí)調(diào)用的計(jì)劃執(zhí)行方法
這時(shí)我們會看到一個(gè)scheduleLaunchActivity方法,表示計(jì)劃加載時(shí)調(diào)用的
這里我門發(fā)現(xiàn)了一個(gè)很有意思的事情
這個(gè)上面我們會看到一個(gè)ActivityClientRecord對象,這個(gè)對象其實(shí)實(shí)際上就是我們的Activity
而且似乎每一個(gè)方法還干了一件讓我們非常熟悉的一件事, 進(jìn)行了一次sendMessage()將當(dāng)前創(chuàng)建的Activity發(fā)送了出去
當(dāng)走到這里我們會發(fā)現(xiàn)最終我們調(diào)用的是Handler的消息通信機(jī)制,也就是說,在這里我們可以總結(jié)一下,
當(dāng)Activity狀態(tài)改變時(shí),都會有對應(yīng)的一個(gè)消息發(fā)送出去
而接收這里,我能發(fā)現(xiàn)通過發(fā)送時(shí)不同的狀態(tài),這邊調(diào)用了不同的handlerXXXActivity方法
在這里,我門貌似發(fā)現(xiàn)了Activity的生命周期的調(diào)用痕跡,那么其實(shí)到此為止,我門可以得出一個(gè)結(jié)論,
Application運(yùn)行的過程當(dāng)中,對于Activity的操作,狀態(tài)轉(zhuǎn)變,其實(shí)實(shí)際上是通過Handler消息機(jī)制來完成的,
Application當(dāng)中只管去發(fā), 由消息機(jī)制負(fù)責(zé)調(diào)用,因?yàn)樵趍ain方法當(dāng)中我門的Looper輪訓(xùn)器是一直在進(jìn)行輪訓(xùn)的
而當(dāng)我們在加載Activity的時(shí)候,當(dāng)中調(diào)用了一個(gè)performLaunchActivity()方法,在這個(gè)中間我發(fā)現(xiàn)了我們onCreate的調(diào)用痕跡
也就是說,到目前為止我們能夠明白,整個(gè)Application加載Activity的整套流程是怎么回事
那么接下來我們需要關(guān)注的是,在onCreate當(dāng)中我們所寫的setContentView到底干了什么
2.setContentView在onCreate當(dāng)中我們往往會使用setContentView去進(jìn)行設(shè)置我們自己的布局文件或者view,那么在這當(dāng)中他到底是怎么做的?通過觀察源碼,這個(gè)時(shí)候通過一系列線索我找到了最終的位置PhoneWindow類
這個(gè)時(shí)候我們會看到他做了兩個(gè)事情,一個(gè)是installDecor,另一個(gè)是inflate,這兩個(gè)后一個(gè)不難猜出他是在進(jìn)行布局文件的解析, 前面的我們認(rèn)為她是在初始化某個(gè)東西
進(jìn)來之后發(fā)現(xiàn)他初始化了兩個(gè)東西,一個(gè)叫做mDecor,一個(gè)叫做mContentParent
我們看到了mDecor是一個(gè)DecorView
mContentParent是一個(gè)ViewGroup
透過注釋的翻譯,其實(shí)我們就能很明確知道這兩個(gè)是用來干嘛的
// This is the view in which the window contents are placed. It is either(這是放置窗口內(nèi)容的視圖)
// mDecor itself, or a child of mDecor where the contents go.(它要么是mDecor本身,要么是mDecor的子類的內(nèi)容。)
//This is the top-level view of the window, containing the window decor.(這是在窗口當(dāng)中的頂層View,包含窗口的decor)
一個(gè)代表的是頂層view,一個(gè)用來裝他下面的視圖內(nèi)容
在接著往下看的時(shí)候,我門發(fā)現(xiàn),generateLayout方法當(dāng)中,發(fā)現(xiàn)了在此處進(jìn)行了大量的requestFeature的調(diào)用,也就是所,我們的requestFeature
然后在下面我門會發(fā)現(xiàn)在做了一件事情,
當(dāng)前這里竟然在加載布局文件,并且生成了一個(gè)view, 但是好像貌似不是我門自己的
所以我們需要去探尋他到底加載了一個(gè)什么東東?
這是我找到了一個(gè)比較有意思的組件,
在這個(gè)上面我看到了一句這樣的注釋
//This is an optimized layout for a screen, with the minimum set of features
enabled.
這是一個(gè)屏幕的優(yōu)化布局,具有最小的特征集啟用。
通過注釋和一些資料分析, 得到了一個(gè)比較坑的結(jié)果。
這是DecorView默認(rèn)的一個(gè)渲染,然后我門自己的布局都是渲染到她的FrameLayout上的
那么在這里我門現(xiàn)在能夠明白,installDector其實(shí)實(shí)際上是在初始化兩個(gè)視圖容器,然后加載系統(tǒng)的R資源及特征,產(chǎn)生了一個(gè)基本布局
那么接著回到之前我門關(guān)注的另外一個(gè)方法mLayoutInflater.inflate(layoutResID, mContentParent);
這個(gè)方法就比較好理解了,
這這段注釋上面我門就可以得到一個(gè)信息
//Inflate a new view hierarchy from the specified xml resource.(從指定的視圖當(dāng)中獲取試圖的層次結(jié)構(gòu),意思就是,現(xiàn)在在加載自己的資源)
而具體流程就不貼代碼了給各位上一張圖
那么在這里我門就能夠明白,setContentView其實(shí)做了兩件比較核心的事情,就是加載環(huán)境配置,和自己的布局,那么接下來我門需要考慮的事情就是,他到底怎么畫到界面上的
3.UI是如何繪制的?通過前面兩個(gè)章節(jié),我門了解到,程序?qū)τ赼ctivity生命周期的調(diào)用,以及我們的視圖資源的由來。這是我門需要找到的是我門的繪制起點(diǎn)在哪?
在ActivityThread啟動時(shí), 我發(fā)現(xiàn)在加載handleLaunchActivity方法調(diào)用performLaunchActivity方法之后又調(diào)用了一個(gè)handleResumeActivity在這里我發(fā)現(xiàn)了繪制流程的開始
通過前面的流程我門知道,onCreate之行完成之后,所有資源交給WindowManager保管
在這里,將我們的VIew交給了WindowManager,此處調(diào)用了addView
進(jìn)入addView之后我們發(fā)現(xiàn)了一段這樣的代碼,他將視圖,和參數(shù)還有我門的一個(gè)ViewRoot對象都用了容器去裝在了起來,那么在此處我門可以得出,是將所有的相關(guān)對象保存起來
mViews保存的是View對象,DecorView
mRoots保存和頂層View關(guān)聯(lián)的ViewRootImpl對象
mParams保存的是創(chuàng)建頂層View的layout參數(shù)。
而WindowManagerGlobal類也負(fù)責(zé)和WMS通信
而在此時(shí),有一句關(guān)鍵代碼root.setView,這里是將我們的參數(shù),和視圖同時(shí)交給了ViewRoot,那么這個(gè)時(shí)候我們來看下ViewRoot當(dāng)中的setView干了什么
終于在這里讓我發(fā)現(xiàn)了讓我明白的一步
在這里我門會看到view.assignParent的設(shè)置是this, 那么也就是說在view當(dāng)中parent其實(shí)實(shí)際上是ViewRoot
那么在setContentView當(dāng)中調(diào)用了一個(gè)setLayoutParams()是調(diào)用的ViewRoot的
而在ViewRoot當(dāng)中發(fā)現(xiàn)了setLayoutParams和preformLayout對requestLayout方法的調(diào)用
在requestLayout當(dāng)中發(fā)現(xiàn)了對scheduleTraversals方法的調(diào)用而scheduleTraversals當(dāng)中調(diào)用了doTraversal的訪問,最終訪問到了performTraversals(),而在這個(gè)里面,我發(fā)現(xiàn)了整體的繪制流程的調(diào)用
當(dāng)前里面依次是用了
UI繪制先回去測量布局,然后在進(jìn)行布局的擺放,當(dāng)所有的布局測量擺放完畢之后,進(jìn)行繪制。
至此整體UI繪制過程我們就已經(jīng)非常清楚了。
我門可以根據(jù)這種繪制的流程來操作自己的自定義組件。
作者:barry 鏈接:https://www.jianshu.com/p/0b1...,轉(zhuǎn)載請注明原創(chuàng)
總結(jié)對于我們APP開發(fā)者來講,建議大家不要以市場行情的變化而受影響,堅(jiān)持自己喜歡人認(rèn)定的路線走下去,沉淀和進(jìn)步!
2018 互聯(lián)網(wǎng)IT開發(fā)者簡歷如何脫穎而出
最新2017(Android)面試題級答案(精選版)
如果有什么的問題,歡迎隨時(shí)來撩我。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/71196.html
摘要:一文教你讀懂云計(jì)算中的那些專有名詞云計(jì)算簡單點(diǎn)講就是把以前需要本地處理器計(jì)算的任務(wù)交到了互聯(lián)網(wǎng)上的服務(wù)器去做。在現(xiàn)代云計(jì)算當(dāng)中扮演著至關(guān)重要的一環(huán),充當(dāng)各元素的橋梁的角色。一文教你讀懂云計(jì)算中的那些專有名詞云計(jì)算(cloud computing)簡單點(diǎn)講就是把以前需要本地處理器計(jì)算的任務(wù)交到了互聯(lián)網(wǎng)上的服務(wù)器去做。是基于互聯(lián)網(wǎng)的相關(guān)服務(wù)的增加、使用和交付模式,通常涉及通過互聯(lián)網(wǎng)來提供動態(tài)易擴(kuò)...
摘要:在較低水平的神經(jīng)元中,一個(gè)多樣性術(shù)語可以揭示一個(gè)特征所代表的不同方面簡單優(yōu)化用多樣性進(jìn)行的優(yōu)化揭示了四個(gè)不同的彎曲的方面。注意勺子的紋理和顏色與狗的皮毛相似,從而足以讓神經(jīng)元激活。下面,一個(gè)神經(jīng)元對兩種類型的動物臉部以及車做出響應(yīng)。 邊緣(層 conv2d0)紋理(層 mixed3a)模式(層 mixed4a)部分(層 mixed4b & mixed4c)目標(biāo)(層 mixed4d & mix...
摘要:是一個(gè)最小的庫,但由于其對尺寸的追求,它的很多代碼可讀性比較差,市面上也很少有全面且詳細(xì)介紹的文章,本篇文章希望能幫助你學(xué)習(xí)的源碼。建議與源碼一起閱讀本文。 作為一名前端,我們需要深入學(xué)習(xí)react的運(yùn)行機(jī)制,但是react源碼量已經(jīng)相當(dāng)龐大,從學(xué)習(xí)的角度,性價(jià)比不高,所以學(xué)習(xí)一個(gè)react mini庫是一個(gè)深入學(xué)習(xí)react的一個(gè)不錯(cuò)的方法。 preact是一個(gè)最小的react mi...
摘要:,,面向切面編程。,切點(diǎn),切面匹配連接點(diǎn)的點(diǎn),一般與切點(diǎn)表達(dá)式相關(guān),就是切面如何切點(diǎn)。例子中,注解就是切點(diǎn)表達(dá)式,匹配對應(yīng)的連接點(diǎn),通知,指在切面的某個(gè)特定的連接點(diǎn)上執(zhí)行的動作。,織入,將作用在的過程。因?yàn)樵创a都是英文寫的。 之前《零基礎(chǔ)帶你看Spring源碼——IOC控制反轉(zhuǎn)》詳細(xì)講了Spring容器的初始化和加載的原理,后面《你真的完全了解Java動態(tài)代理嗎?看這篇就夠了》介紹了下...
閱讀 1531·2023-04-25 16:31
閱讀 2110·2021-11-24 10:33
閱讀 2802·2021-09-23 11:33
閱讀 2619·2021-09-23 11:31
閱讀 3021·2021-09-08 09:45
閱讀 2408·2021-09-06 15:02
閱讀 2725·2019-08-30 14:21
閱讀 2376·2019-08-30 12:56