新聞中心
小編給大家分享一下UI繪制流程是怎么樣的,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
目前創(chuàng)新互聯(lián)已為1000+的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管、網(wǎng)站改版維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、蒙山網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。前言
在android當(dāng)中對(duì)于UI體系當(dāng)中往往我們會(huì)在繪制UI的時(shí)候碰到各種各樣的問(wèn)題而不知道從何解決, 也有時(shí)需要開(kāi)發(fā)更改自定義組件時(shí),需要做自己的調(diào)整,或者是實(shí)現(xiàn)某個(gè)自定義特效時(shí)的思路不明確,想要達(dá)到去玩轉(zhuǎn)UI的最為基礎(chǔ)的部分,就是去全面的深入了解UI的繪制流程.所以接下來(lái)帶大家去進(jìn)行全面分析UI整體的繪制體系.
思路:android程序啟動(dòng)-→Activity加載并完成生命周期-→setContentView-→圖形繪制
疑惑:
1.Android程序是如何啟動(dòng),Activity生命周期如何調(diào)用?
2.在Activity onCreate當(dāng)中我們的setContentView是如何將UI文件加載?
3.UI是如何繪制的?
答案:
1.Android程序流程
眾所周知,我們的java程序想要開(kāi)啟需要依賴(lài)于main方法,也就是我們的程序入口(主線程)進(jìn)入,但是在我們?nèi)粘i_(kāi)發(fā)android程序的過(guò)程當(dāng)中我們并沒(méi)有發(fā)現(xiàn)main方法的存在,那么android當(dāng)中的是如何開(kāi)始運(yùn)行的?
熟悉的朋友們可能都知道在android當(dāng)中存在一個(gè)叫做ActivityThread的類(lèi),這個(gè)類(lèi)代表的是android當(dāng)中的主線程,而在這個(gè)類(lèi)當(dāng)中我們看到了比較熟悉的main方法,那么現(xiàn)在是否可以認(rèn)為我們的android在打開(kāi)app時(shí)是首先調(diào)用的是當(dāng)前這個(gè)類(lèi)的main,也就是此處為我們的啟動(dòng)點(diǎn)
在此處可以看到Activity調(diào)用了一個(gè)attach()方法
在這里我們可能首先要考慮的是getService拿出來(lái)的是什么?
進(jìn)去之后,我們會(huì)發(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)用管理,并且通過(guò)在binder接口當(dāng)中進(jìn)行調(diào)用,這也是為什么我們講Activity是跨進(jìn)程訪問(wèn)的原因
那么明白了這個(gè)時(shí)候能夠得到ActivityManager之后,我們接著回到attach當(dāng)中繼續(xù)看下去, 這個(gè)時(shí)候會(huì)發(fā)現(xiàn),我們調(diào)用了一個(gè)attachApplication方法(見(jiàn)圖2)這個(gè)方法又是干嘛的?attachApplication在這里的作用其實(shí)實(shí)際上是ActivityThread通過(guò)attach獲取到,然后將applciationThread將其關(guān)聯(lián),把a(bǔ)ctivity相關(guān)信息存儲(chǔ)在applciationThread里面,apllicationThread的類(lèi)為activity的各種狀態(tài)做了相對(duì)應(yīng)的準(zhǔn)備工作
這個(gè)時(shí)候我們需要關(guān)注,ApplicationThread當(dāng)中做了什么?
當(dāng)我們打開(kāi)ApplicationThread中我們會(huì)看到一堆的schedle方法,這些方法的名稱(chēng)其實(shí)就可以給我們表明,代表的是在執(zhí)行Activity的某種狀態(tài)時(shí)調(diào)用的計(jì)劃執(zhí)行方法
這時(shí)我們會(huì)看到一個(gè)scheduleLaunchActivity方法,表示計(jì)劃加載時(shí)調(diào)用的
這里我發(fā)現(xiàn)了一個(gè)很有意思的事情
這個(gè)上面我們會(huì)看到一個(gè)ActivityClientRecord對(duì)象,這個(gè)對(duì)象其實(shí)實(shí)際上就是我們的Activity
而且似乎每一個(gè)方法還干了一件讓我們非常熟悉的一件事, 進(jìn)行了一次sendMessage()將當(dāng)前創(chuàng)建的Activity發(fā)送了出去
當(dāng)走到這里我們會(huì)發(fā)現(xiàn)最終我們調(diào)用的是Handler的消息通信機(jī)制,也就是說(shuō),在這里我們可以總結(jié)一下,
當(dāng)Activity狀態(tài)改變時(shí),都會(huì)有對(duì)應(yīng)的一個(gè)消息發(fā)送出去
而接收這里,我能發(fā)現(xiàn)通過(guò)發(fā)送時(shí)不同的狀態(tài),這邊調(diào)用了不同的handlerXXXActivity方法
在這里,我門(mén)貌似發(fā)現(xiàn)了Activity的生命周期的調(diào)用痕跡,那么其實(shí)到此為止,我門(mén)可以得出一個(gè)結(jié)論,
Application運(yùn)行的過(guò)程當(dāng)中,對(duì)于Activity的操作,狀態(tài)轉(zhuǎn)變,其實(shí)實(shí)際上是通過(guò)Handler消息機(jī)制來(lái)完成的,
Application當(dāng)中只管去發(fā), 由消息機(jī)制負(fù)責(zé)調(diào)用,因?yàn)樵趍ain方法當(dāng)中我門(mén)的Looper輪訓(xùn)器是一直在進(jìn)行輪訓(xùn)的
而當(dāng)我們?cè)诩虞dActivity的時(shí)候,當(dāng)中調(diào)用了一個(gè)performLaunchActivity()方法,在這個(gè)中間我發(fā)現(xiàn)了我們onCreate的調(diào)用痕跡
也就是說(shuō),到目前為止我們能夠明白,整個(gè)Application加載Activity的整套流程是怎么回事
那么接下來(lái)我們需要關(guān)注的是,在onCreate當(dāng)中我們所寫(xiě)的setContentView到底干了什么
2.setContentView
在onCreate當(dāng)中我們往往會(huì)使用setContentView去進(jìn)行設(shè)置我們自己的布局文件或者view,那么在這當(dāng)中他到底是怎么做的?通過(guò)觀察源碼,這個(gè)時(shí)候通過(guò)一系列線索我找到了最終的位置PhoneWindow類(lèi)
這個(gè)時(shí)候我們會(huì)看到他做了兩個(gè)事情,一個(gè)是installDecor,另一個(gè)是inflate,這兩個(gè)后一個(gè)不難猜出他是在進(jìn)行布局文件的解析, 前面的我們認(rèn)為她是在初始化某個(gè)東西
進(jìn)來(lái)之后發(fā)現(xiàn)他初始化了兩個(gè)東西,一個(gè)叫做mDecor,一個(gè)叫做mContentParent
我們看到了mDecor是一個(gè)DecorView
mContentParent是一個(gè)ViewGroup
透過(guò)注釋的翻譯,其實(shí)我們就能很明確知道這兩個(gè)是用來(lái)干嘛的
// 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的子類(lèi)的內(nèi)容。)
//This is the top-level view of the window, containing the window decor.(這是在窗口當(dāng)中的頂層View,包含窗口的decor)
一個(gè)代表的是頂層view,一個(gè)用來(lái)裝他下面的視圖內(nèi)容
在接著往下看的時(shí)候,我門(mén)發(fā)現(xiàn),generateLayout方法當(dāng)中,發(fā)現(xiàn)了在此處進(jìn)行了大量的requestFeature的調(diào)用,也就是所,我們的requestFeature
然后在下面我門(mén)會(huì)發(fā)現(xiàn)在做了一件事情,
當(dāng)前這里竟然在加載布局文件,并且生成了一個(gè)view, 但是好像貌似不是我門(mén)自己的
所以我們需要去探尋他到底加載了一個(gè)什么東東?
這是我找到了一個(gè)比較有意思的組件,
在這個(gè)上面我看到了一句這樣的注釋
//This is an optimized layout for a screen, with the minimum set of features
enabled.
這是一個(gè)屏幕的優(yōu)化布局,具有最小的特征集啟用。
通過(guò)注釋和一些資料分析, 得到了一個(gè)比較坑的結(jié)果。
這是DecorView默認(rèn)的一個(gè)渲染,然后我門(mén)自己的布局都是渲染到她的FrameLayout上的
那么在這里我門(mén)現(xiàn)在能夠明白,installDector其實(shí)實(shí)際上是在初始化兩個(gè)視圖容器,然后加載系統(tǒng)的R資源及特征,產(chǎn)生了一個(gè)基本布局
那么接著回到之前我門(mén)關(guān)注的另外一個(gè)方法mLayoutInflater.inflate(layoutResID, mContentParent);
這個(gè)方法就比較好理解了,
這這段注釋上面我門(mén)就可以得到一個(gè)信息
//Inflate a new view hierarchy from the specified xml resource.(從指定的視圖當(dāng)中獲取試圖的層次結(jié)構(gòu),意思就是,現(xiàn)在在加載自己的資源)
而具體流程就不貼代碼了給各位上一張圖
那么在這里我門(mén)就能夠明白,setContentView其實(shí)做了兩件比較核心的事情,就是加載環(huán)境配置,和自己的布局,那么接下來(lái)我門(mén)需要考慮的事情就是,他到底怎么畫(huà)到界面上的
3.UI是如何繪制的?
通過(guò)前面兩個(gè)章節(jié),我門(mén)了解到,程序?qū)τ赼ctivity生命周期的調(diào)用,以及我們的視圖資源的由來(lái)。這是我門(mén)需要找到的是我門(mén)的繪制起點(diǎn)在哪?
在ActivityThread啟動(dòng)時(shí), 我發(fā)現(xiàn)在加載handleLaunchActivity方法調(diào)用performLaunchActivity方法之后又調(diào)用了一個(gè)handleResumeActivity在這里我發(fā)現(xiàn)了繪制流程的開(kāi)始
通過(guò)前面的流程我門(mén)知道,onCreate之行完成之后,所有資源交給WindowManager保管
在這里,將我們的VIew交給了WindowManager,此處調(diào)用了addView
進(jìn)入addView之后我們發(fā)現(xiàn)了一段這樣的代碼,他將視圖,和參數(shù)還有我門(mén)的一個(gè)ViewRoot對(duì)象都用了容器去裝在了起來(lái),那么在此處我門(mén)可以得出,是將所有的相關(guān)對(duì)象保存起來(lái)
mViews保存的是View對(duì)象,DecorView
mRoots保存和頂層View關(guān)聯(lián)的ViewRootImpl對(duì)象
mParams保存的是創(chuàng)建頂層View的layout參數(shù)。
而WindowManagerGlobal類(lèi)也負(fù)責(zé)和WMS通信
而在此時(shí),有一句關(guān)鍵代碼root.setView,這里是將我們的參數(shù),和視圖同時(shí)交給了ViewRoot,那么這個(gè)時(shí)候我們來(lái)看下ViewRoot當(dāng)中的setView干了什么
終于在這里讓我發(fā)現(xiàn)了讓我明白的一步
在這里我門(mén)會(huì)看到view.assignParent的設(shè)置是this, 那么也就是說(shuō)在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對(duì)requestLayout方法的調(diào)用
在requestLayout當(dāng)中發(fā)現(xiàn)了對(duì)scheduleTraversals方法的調(diào)用而scheduleTraversals當(dāng)中調(diào)用了doTraversal的訪問(wèn),最終訪問(wèn)到了performTraversals(),而在這個(gè)里面,我發(fā)現(xiàn)了整體的繪制流程的調(diào)用
當(dāng)前里面依次是用了
UI繪制先回去測(cè)量布局,然后在進(jìn)行布局的擺放,當(dāng)所有的布局測(cè)量擺放完畢之后,進(jìn)行繪制。
以上是“UI繪制流程是怎么樣的”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道!
當(dāng)前文章:UI繪制流程是怎么樣的-創(chuàng)新互聯(lián)
文章路徑:http://www.ef60e0e.cn/article/csdsce.html