轉載請注明 Android_YangKe,謝謝饶辙!
老實說自己做 Android 有一段時間了耳幢,但發(fā)現(xiàn) Android 技能提升上有了點小瓶頸,總感覺自己什么都會禁悠,又都感覺自己什么都不會念祭,于是就有了此片文章。
下面我們將通過 Window 慢慢引出三者之間的關系碍侦,同時適當?shù)脑创a輔助分析粱坤。說到源碼相信很多人都是心中都一萬個 mmb,勞資這么差的英文瓷产,動不動成千上萬行的代碼站玄,腦袋瞬間短路好不好... 微笑-微笑 。
Activity濒旦,View 是什么我相信不用解釋株旷,而 Window 在使用頻率上相對來說就低了些,那么 Window 是什么尔邓?在 Android 體系中扮演著什么樣的角色晾剖?下面是 Google 工程師對 Window 類的一些介紹,我們來看下铃拇。
//Window.java
/**
* Abstract base class for a top-level window look and behavior policy. An
* instance of this class should be used as the top-level view added to the
* window manager. It provides standard UI policies such as a background, title
* area, default key processing, etc.
*
* <p>The only existing implementation of this abstract class is
* android.view.PhoneWindow, which you should instantiate when needing a
* Window.
*/
大致意思:Window 是一個基礎類钞瀑,是頂級視圖的承載。提供了標準的 UI 策略慷荔,如背景雕什,標題。同時 Window 只有一個實現(xiàn)類PhoneWindow
显晶。官方的解釋還是比較給力贷岸,很詳細的介紹了該對象,現(xiàn)在我們對 Window 有了一個初步認識磷雇。下面我們將結合具體案例進行探索偿警。
Activity 中 onCreate 函數(shù)相信大家再熟悉不過了,如我們將里面的setContentView
函數(shù)注釋掉時唯笙,會發(fā)現(xiàn)原來我們的炫酷的頁面只留下一個標題加空白頁面(前提我們沒有修改默認的主題)螟蒸,這么看來此行代碼很關鍵盒使。
//Activity.java
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
一般來說我們的 Activity 都是繼承自 AppCompatActivity
,但最終的頂層父類是 Activity七嫌。通過上面源碼我們可以發(fā)現(xiàn) Activity 只是 View 宿主少办,并沒有真正的實現(xiàn)setContentView
而是通過 getWindow 操作此函數(shù),我們來看下 getWindow诵原。
//Activity.java
public Window getWindow() {
return mWindow;
}
final void attach(...) {
attachBaseContext(context);
mWindow = new PhoneWindow(this, window,activityConfigCallback);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
...
}
很簡單 getWindow 函數(shù)返回了一個實例PhoneWindow
英妓。由于代碼中沒有對 getWindow 判空,我們可以推測出 attach 函數(shù)一定在 setContentView
之前執(zhí)行绍赛,也就是 onCreate 函數(shù)之前蔓纠,不然一定會報NullPointerException
。
扯得有點多吗蚌,言歸正傳腿倚。這里我們看到了 Window 的身影,從上文我們了解到 Window 是頂級視圖的承載褪测,而PhoneWindow
又是 Window 的唯一子類猴誊,我們嘗試著去 PhoneWindow
中探索 setContentView
。
//PhoneWindow.java
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
ViewGroup mContentParent;
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
...
}
一大串代碼(當然我省略了一部分代碼)果不其然侮措,真正的操作的就是在 Window 的 setContentView
函數(shù)中完成的,首先乖杠。
- mDecor:Window 上最頂層的視圖分扎,如果按照從上到下的順序,分別是狀態(tài)欄胧洒,標題欄畏吓,具體 View 控件。由于其繼承了 FrameLayout 也就是說 mDecor 也是一個 ViewGroup卫漫。
- mContentParent:表示視圖區(qū)域菲饼,里面可以是 mDecor,也可以是 mDecor 中的具體 View列赎,但不代表具體視圖宏悦。
了解了這兩個對象的作用,我們繼續(xù)看代碼包吝。removeAllViews
函數(shù)顧名思義饼煞,也就是從當前 Window 中移除所有 View,這里就不進入源碼進行分析了(代碼水很深诗越,隨時保留精氣神)∽┣疲現(xiàn)在就剩下installDecor
了,此函數(shù)貌似很關鍵嚷狞,我們跟進來看下块促。
//PhoneWindow.java
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor(-1);
...
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
...
}
}
首先映入眼簾的是generateDecor
荣堰,同時此函數(shù)的返回值賦予了 mDecor。隨后系統(tǒng)調用了generateLayout
竭翠。generateLayout
從字面意義上來看是初始化布局持隧,莫非跟布局 View 有關,我們來看一下逃片。
//PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme.
TypedArray a = getWindowStyle();
if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
// Don't allow an action bar if there is no title.
requestFeature(FEATURE_ACTION_BAR);
}
if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
}
...
}
這里我們拋去 if 的各種判斷直接看這幾個常量:FLAG_FULLSCREEN
屡拨、 FEATURE_NO_TITLE
、 FLAG_FULLSCREEN
等等褥实,是不是似曾相識呢呀狼?相信大家在 onCreate 函數(shù)setContentView
前都有過重設當前 Activity 樣式的經(jīng)歷,嚴格來說應該是 Window (Activity 全屏损离、去除標題欄)哥艇。也就是說屏幕上頁面的尺寸,樣式都是通過 Window 來控制的僻澎!看來此函數(shù)很重要貌踏,打起精神,我們再來分析一波窟勃。
//PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
// Remaining setup -- of background and title -- that only applies
// to top-level windows.
WindowManager.LayoutParams params = getAttributes();
if (!hasSoftInputMode()) {
params.softInputMode = a.getInt(R.styleable.Window_windowSoftInputMode, params.softInputMode);
}
if (params.windowAnimations == 0) {
params.windowAnimations = a.getResourceId(R.styleable.Window_windowAnimationStyle, 0);
}
...
if (getContainer() == null) {
final Drawable background;
if (mBackgroundResource != 0) {
background = getContext().getDrawable(mBackgroundResource);
} else {
background = mBackgroundDrawable;
}
mDecor.setWindowBackground(background);
final Drawable frame;
if (mFrameResource != 0) {
frame = getContext().getDrawable(mFrameResource);
} else {
frame = null;
}
mDecor.setWindowFrame(frame);
...
if (mTitle != null) {setTitle(mTitle);}
if (mTitleColor == 0) {mTitleColor = mTextColor;}
setTitleColor(mTitleColor);
}
mDecor.finishChanging();
return contentParent;
}
首先我們看下官方給的注釋:
- Remaining setup -- of background and title -- that only applies to top-level windows.
將自己置身于情境之中祖乳,大概意思:設置標題,背景顏色秉氧,將視圖應用在頂層 View 上眷昆,誰呢?DecorView汁咏。
其次:
獲取 Window 的一些屬性亚斋,并根據(jù)情況對輸入法模式、載入動畫等等進行配置攘滩。
最后:
對 Window 承載的視圖進行背景設置帅刊,邊距設置,標題欄顏色設置漂问,標題欄設置等等赖瞒。
到這里相信你對 Window 的作用,以及其在 Android 中扮演著怎樣的角色有了一定的認知级解。下面我們來看一張圖片冒黑,輔助我們理解 Activity、Window勤哗、View 之間的關系:(圖片源自互聯(lián)網(wǎng)抡爹,出處不明)
最外層是 Activity、其次是 PhoneWindow芒划、最后是我們常操作的 View 控件冬竟。通過這張圖相信你對 Activity欧穴、Window、View 有了進一步的認識泵殴,下面我們再來重新認識下三者涮帘。
View:說到 View 相信大家都很熟悉,像什么 TextView笑诅、Button调缨、ImageView 等等我相信你可以一口氣說一大堆。View 是具體視圖的最小展示單元吆你。在頁面上可以是一張圖片弦叶,一段文本,一個網(wǎng)頁妇多。簡而言之:View 就是具體視圖(常常與用戶打交道)伤哺。
Window:我們真正意義上所說的頁面,是 Activity 任命的大使者祖,主要用于管理 View立莉,設置窗口(視圖)樣式、尺寸七问、輸入法模式等蜓耻。我們也可以通過WindowManager
對 View 進行添加和移除操作等。簡而言之:Window 主要用于控制顯示窗口的尺寸烂瘫、樣式媒熊、View 的移除添加(常常與研發(fā)人員打交道)。
Activity:頁面的載體坟比。維護應用程序的生命周期、提供用戶處理事件的 API嚷往、進程間通信等葛账。簡而言之:用于管理系統(tǒng)組件相關事物。
整理:
Activity-> PhoneWindow-> DecorView皮仁。
總結:
Activity 作為四大組件主要與系統(tǒng)進行交互籍琳,用于組件間通信,生命周期管理贷祈、進程通信等趋急。Window 作為視圖載體,主要用于管理視圖的尺寸势誊、樣式呜达、輸入法模式、View 的移除添加等粟耻,需要依托于 Activiity查近。View 就比較簡單了眉踱,不同的 View 用于展示不同的視圖,例:文本組件霜威,圖片組件谈喳,甚至網(wǎng)頁等,需要依托于 Window戈泼。也就是說三者相輔相成婿禽,誰離開都將無存在意義。
尾聲:
為什么 View 不直接與 Activity 關聯(lián)呢大猛?反而又設計出一個 Window 對象扭倾?
其實這里有些面向對象的概念,也就是說對于龐大的功能我們需要進行拆分胎署,讓其盡量獨立吆录,各司其職,同時在功能互不影響的情況下琼牧,相輔相成恢筝。
完~
喜歡有幫助的話: 雙擊、評論巨坊、轉發(fā)撬槽,動一動你的小手讓更多的人知道!