Android 面試官:簡述一下 View 的繪製流程,這個都答不出來就別想拿Offer了
前言
作為一名Android開發者肯定明白View的地位,說它佔據半壁江山也不為過,作為基石之一,搞明白它的載入流程是每個開發者都應該去做的,目前網路上很多關於View繪製流程的文章,有些質量也很高,但我還是想以自己的思路出一篇文章。相信讀完你對View的工作機制以及自定義View會有一個全新的認識。
1. View的繪製時機
1.1. 知識儲備
- Window:每個
Activity
都會建立一個Window
用於承載View檢視的顯示,Window
是一個抽象類存在了一個唯一實現類PhoneWindow
- DecorView:最頂層的View,是一個
FrameLayout
子類,最終會被載入到Window當中,它內部只有一個垂直方向的LinearLayout
分為兩部分:- TitleBar:螢幕頂部的狀態列
- ContentView:
Activity
對應的XML佈局,透過setContentView
設定到DecorView
中。
1.2. Activity、Window、DecorView之間關係
首先來看一下Activity中setContentView原始碼:
從程式碼可以看出,
Activity
的
setContentView
實質是將
View
傳遞到
Window
的
setContentView()
方法中,
Window
的
setContenView
會在內部呼叫
installDecor()
方法建立
DecorView
,看一下它的部分原始碼:
透過
generateDecor()
new一個
DecorView
,然後呼叫
generateLayout()
獲取
DecorView
中
content
,最終透過
inflate
將
Activity
檢視新增到
DecorView
中的
content
中,但此時
DecorView
還未被新增到
Window
中。新增操作需要藉助
ViewRootImpl
。
ViewRootImpl
的作用是用來銜接
WindowManager
和
DecorView
,在
Activity
被建立後會透過
WindowManager
將
DecorView
新增到
PhoneWindow
中並且建立
ViewRootImpl
例項,隨後將
DecorView
與
ViewRootImpl
進行關聯,最終透過執行
ViewRootImpl
的
performTraversals()
開啟整個View樹的繪製。
關於Activity在何時將DecorView新增到Window以及何時建立 ViewRootImpl,這塊內容牽扯麵比較廣,涉及到Activity啟動流程、ActivityManagerService(AMS)、WindowManagerService(WMS),內容太過於深入加上作者能力有限就不誤人子弟了。如有興趣推薦查閱劉皇叔《Android進階解密》,書中對這方面內容講解還是比較全面的 。
2. 繪製過程
從第一小節可知,View的繪製是從
ViewRootImpl
的
performTraversals()
方法開始,從最頂層的
View(ViewGroup)
開始逐層對每個
View
進行繪製操作,下面來看一下該方法部分原始碼:
這方法大概有幾百行,機智的作者抽出三句精華呈現給大家~~~
- measure:為測量寬高過程,如果是ViewGroup還要在onMeasure中對所有子View進行measure操作。
- layout:用於擺放View在ViewGroup中的位置,如果是ViewGroup要在onLayout方法中對所有子View進行layout操作。
- draw:往View上繪製影像。
示意圖如下:
確實不想畫圖了,從剛哥的書裡拍一張吧~~~
2.1 Measure
performMeasure()
原始碼
可以看出從mView(最頂層ViewGroup)開始進行測量操作,然後逐層遍歷View並執行measure操作。
MeasureSpac
Measure
是
View
繪製三個過程中的第一步,提到
Measure
就不得不提
MeasureSpac
它是一個32位
int
型別數值,高兩位
SpacMode
代表測量模式,低30位
SpacSize
代表測量尺寸,是View的內部類,原始碼如下:
內部也包含三種測量模式:
-
UNSPECIFIED :父佈局不會對子View做任何限制,例如我們常用的
ScrollView
就是這種測量模式。 -
EXACTLY :精確數值,比如使用了
match_parent
或者xxxdp,表示父佈局已經決定了子View
的大小,通常在這種情況下View
的尺寸就是SpacSize
-
AT_MOST :自適應,對應
wrap_content
子View可以根據內容設定自己的大小,但前提是不能超出父ViewGroup
的寬高。
注意點:
在我們自定義View的過程中都會在onMeasure中進行寬高的測量,這個方法會從父佈局中接收兩個引數
widthMeasureSpac
和heightMeasureSpac
,所以子佈局的寬高大小需要受限於父佈局。
在自定義View寬高測量的過程中,我們需要獲取
MeasurSpac
中的寬高和測量模式,自定義
ViewGroup
也必須給子View傳遞
MeasurSpac
,Android也給我們提供了計算
MeasurSpac
和透過
MeasurSpac
獲取相應值的方式,都位於
MeasurSpac
中,具體程式碼如下:
從
ViewGroup
到
View
對尺寸和模式進行了一次封裝和拆解,其目的是為了減少物件的建立,避免造成不必要的記憶體浪費。
LayoutParams
在剛接觸Android的時候經常有一個疑問,為什麼View設定自己的寬高,還要建立一個
xxx.LayoutParams
?前面也提到了,子View的寬高是要受限於父佈局的,所以不能透過
setWidth
或者
setHeight
直接設定寬高的,另外
LayoutParams
的作用不僅如此,比如一個View的父佈局是
RelativeLayout
,可以透過設定
RelativeLayout.LayoutParams
的
above
,
below
等屬性來調整在父佈局中的位置。
自定義View寬高測量演示
建立一個類繼承View,重寫其
onMeasure()
方法
一般的自定義View中,如果對寬高沒有特殊需求可直接透過
getDefaultSize()
方法獲取,該方法位於View中原始碼如下:
從程式碼分析可知,獲取
mode
和
size
後會分別對三種測量模式進行判斷,
UNSPECIFIED
使用預設尺寸,而
AT_MOST
和
EXACTLY
使用父佈局給出的測量尺寸。尺寸計算完畢後透過
setMeasuredDimension(width,height)
設定最終寬高。
2.2 Layout
performLayout()
部分原始碼:
跟measure類似,同樣是從
mView(最頂層ViewGroup)
開始進行
layout
操作,隨後逐層遍歷。
layout(l,t,r,b)
四個引數分別對應
左上右下
的位置,從而確定View在ViewGroup中的位置。下面來看一下
layout()
部分原始碼:
結合原始碼可知
layout()
會將四個位置引數傳遞給
setOpticalFrame()
或者
setFrame()
,而
setOpticalFrame()
內部會呼叫
setFrame()
,所以最終透過
setFrame()
確定
View
在
ViewGroup
中的位置。位置確定完畢會呼叫
onLayout(l,t,r,b)
對子View進行擺放。
onLayout()
View
和
ViewGroup
在執行完
setFrame()
後都會呼叫
onLayout()
方法,但上面也有提到該方法的作用是對子View進行位置擺放,所以單一View是不需要重寫此方法。而
ViewGroup
會根據自己的特性任意對子View進行擺放。
2.3 Draw
相信很多學習自定義View的同學都是奔著有朝一日自己也實現那些眼花繚亂的效果,起碼我自己就是。我們在手機上看到的那些五彩繽紛的圖片,動畫都是在這個方法內繪製而成。
相比於measure和layout階段,draw階段中View和ViewGroup變得沒那麼緊密了,View的繪製過程中不需要考慮ViewGroup,而ViewGroup也只需觸發子View的繪製方法即可。
performDraw()
執行後同樣會從根佈局開始逐層對每個View進行draw操作,在View中繪製操作時透過
draw()
進行,來看一下其主要原始碼:
draw()方法中主要包含四部分內容,其中我們開發者只需要關心onDraw(canvas)即可,即自身的內容繪製。
繪製內容簡述
關於繪製內容這部分可利用到的知識點很多,多到可以寫一本書出來,所以僅靠本文全部詳細描述顯然是不現實的。下面我羅列一部分常用內容供大家參考:
- Canvas:畫布,不管是文字,圖形,圖片都要透過畫布繪製而成
- Paint:畫筆,可設定顏色,粗細,大小,陰影等等等等,一般配合畫布使用
- Path:路徑,用於形成一些不規則圖形。
- Matrix:矩陣,可實現對畫布的幾何變換。
總結
文章從四個方面總結了View的繪製流程:
繪製時機
,
寬高測量
,
位置擺放
,
影像繪製
,因為側重於流程所以只是把這四部分的精華給拎出來分享給大家,起到一個拋磚引玉的作用,想要透徹理解啟動流程、玩轉自定義View還需要對各部分知識系統的學習。
如何系統學習Android呢?
這裡今天給大家分享一份Android進階學習資料,主要為安卓相關知識點及面試資料為主,在這個PDF中,透過 詳解各大網際網路公司的 Android 常見面試題為主線,從面試的角度帶你介紹必備知識點,以及該知識點在專案中的實際應用。
幫你在現在的基礎上,重新梳理和建立 Android 開發的知識體系。無論是你短期內想提升 Android 內功實力,突破自己工作中的能力瓶頸,還是準備參加 Android 面試,都會在這個PDF中有所收穫。一些基礎不好的,這裡也有一份安卓基礎資料包,幫助鞏固基礎。
以下是這份PDF主要內容:
- Android 核心技術:介紹 Android 開發中常用的核心技術,比如自定義 View、Handler,以及一些開源框架的原理實現,來夯實你的底層能力。只有底層能力足夠出色,之後的進階之路才會更加輕鬆。
- 常見問題剖析:介紹一些專案中常見的疑難問題,使你能夠對現有專案做出合理的重構最佳化。
1、確定好方向,梳理成長路線圖
不用多說,相信大家都有一個共識:無論什麼行業,最牛逼的人肯定是站在金字塔端的人。所以,想做一個牛逼的程式設計師,那麼就要讓自己站的更高,成為技術大牛並不是一朝一夕的事情,需要時間的沉澱和技術的積累。
關於這一點,在我當時確立好Android方向時,就已經開始梳理自己的成長路線了,包括技術要怎麼系統地去學習,都列得非常詳細。
知識梳理完之後,就需要進行查漏補缺,所以針對這些知識點,我手頭上也準備了不少的電子書和筆記,這些筆記將各個知識點進行了完美的總結:
2、透過原始碼來系統性地學習
只要是程式設計師,不管是Java還是Android,如果不去閱讀原始碼,只看API文件,那就只是停留於皮毛,這對我們知識體系的建立和完備以及實戰技術的提升都是不利的。
真正最能鍛鍊能力的便是直接去閱讀原始碼,不僅限於閱讀各大系統原始碼,還包括各種優秀的開源庫。
3、閱讀前輩的一些技術筆記
4、刷題備戰,直通大廠
歷時半年,我們整理了這份市面上最全面的安卓面試題解析大全
包含了騰訊、百度、小米、阿里、樂視、美團、58、360、新浪、搜狐等一線網際網路公司面試被問到的題目。熟悉本文中列出的知識點會大大增加透過前兩輪技術面試的機率。
如何使用它?
1.可以透過目錄索引直接翻看需要的知識點,查漏補缺。
2.五角星數表示面試問到的頻率,代表重要推薦指數
以上文章中的資料,均可以免費分享給大家來學習,無論你是零基礎還是工作多年,現在開始就不會晚。
以上內容均放在了開源專案: 【 github 】 中已收錄,大家可以自行獲取。
學習技術是一條慢長而艱苦的道路,不能靠一時激情,也不是熬幾天幾夜就能學好的,必須養成平時努力學習的習慣。所以: 貴在堅持!
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69983917/viewspace-2733351/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Android View繪製流程看這篇就夠了AndroidView
- 每日一問:簡述 View 的繪製流程View
- 面試官的“芳心”就這樣被我俘獲!別的不會,就會拿Offer面試
- 探究Android View 繪製流程,Canvas 的由來AndroidViewCanvas
- Flutter的繪製流程簡述Flutter
- View的繪製二:View的繪製流程View
- 面試官問你 - 自定義View跟繪製流程相關知識點??面試View
- Android進階(五)View繪製流程AndroidView
- Android View繪製原理:繪製流程排程、測算等AndroidView
- Android原始碼分析之View繪製流程Android原始碼View
- 探究 Android View 繪製流程,Activity 的 View 如何展示到螢幕AndroidView
- View 繪製流程分析View
- Spring Boot 面試,一個問題你就答不上來了Spring Boot面試
- 百度Android面試真題解析:二次面試終拿到offer,這些面試重點我都整理出來了!Android面試
- 那些簡歷造假拿 Offer 的程式設計師,後來都怎麼樣了?程式設計師
- 邦芒面試:這10個問題都答不上來,你還想透過面試?面試
- Android View的繪製過程AndroidView
- View的繪製-measure流程詳解View
- Android系統原始碼分析--View繪製流程之-inflateAndroid原始碼View
- Android系統原始碼分析–View繪製流程之-setContentViewAndroid原始碼View
- Android系統原始碼分析--View繪製流程之-setContentViewAndroid原始碼View
- View繪製流程原始碼分析View原始碼
- Android面試必問!View 事件分發機制,看這一篇就夠了!Android面試View事件
- Android高階進階之路【一】Android中View繪製流程淺析AndroidView
- 面試時寫不出排序演算法?看這篇就夠了。面試排序演算法
- 面試時寫不出排序演算法?看這篇就夠了面試排序演算法
- 求助,這幾道面試題有些我回答不出來了面試題
- 學完了這篇JVM,面試官真拿我沒辦法了!JVM面試
- 面試官:你都工作3年了,這個演算法題都不會?面試演算法
- Android自定義View之(一)View繪製流程詳解——向原始碼要答案AndroidView原始碼
- 幹趴面試官系列 | 請你簡述一下Kafka中的分割槽分配面試Kafka
- Android View 原始碼解析(三) – View的繪製過程AndroidView原始碼
- View繪製01-Android渲染系統中的ViewViewAndroid
- 瞭解了這些,輕鬆拿offer——Java面試之道Java面試
- 看完這篇HTTP,跟面試官扯皮就沒問題了HTTP面試
- 面試 HTTP ,99% 的面試官都愛問這些問題面試HTTP
- Android View繪製原始碼分析 MeasureAndroidView原始碼
- 2018.03.15、View 繪製流程學習 筆記View筆記