1.簡介
Activity
Activity并不負(fù)責(zé)視圖控制,它只是控制生命周期和處理事件霜浴。真正控制試圖的是Window。一個(gè)Activity包含了一個(gè)Window蓝纲,Window才是真正的代表一個(gè)窗口阴孟。Activity就像一個(gè)控制器,統(tǒng)籌視圖的添加與顯示税迷,以及通過其他回調(diào)方法永丝,來與Window、以及View進(jìn)行交互箭养。
DecorView
DecorView是Fragment的子類慕嚷,它可以被認(rèn)為是Android視圖樹的根節(jié)點(diǎn)視圖。DecorView作為頂級(jí)View毕泌,一般情況下它內(nèi)部包含一個(gè)樹直方向的LinearLayout喝检,這個(gè)LinearLayout里面上下包含3個(gè)部分,上面是ViewStub撼泛,延遲加載的視圖(應(yīng)該是設(shè)置ActionBar挠说,根據(jù)Theme設(shè)置),中間的是標(biāo)題欄(根據(jù)Theme設(shè)置愿题,有的布局沒有)损俭,下面的是內(nèi)容欄蛙奖。例如:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<ViewStub
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>
在Activity中通過setContentView所設(shè)置的布局文件其實(shí)就是被加載到內(nèi)容欄之中的,成為其唯一子View杆兵,就是上面的id為content的FrameLayout中雁仲,在代碼中可以通過content來得到對(duì)應(yīng)加載的布局。
ViewGroup content = findViewById(R.id.content);
ViewGroup rootView = (ViewGroup) content.getChildAt(0)
ViewRoot
所有View的繪制以及事件分發(fā)等交互都是通過它里執(zhí)行或傳遞的琐脏。
ViewRoot對(duì)應(yīng)的ViewRootImpl類攒砖,它是連接WindowManagerService和DecorView的紐帶,View的三大流程(測量(measure)骆膝,布局(layout)祭衩,繪制(draw))均通過ViewRoot來完成。
ViewRoot并不屬于View樹的一份子阅签。從源碼的實(shí)現(xiàn)上看掐暮,它既非View的子類,也非View的父類政钟,但是它實(shí)現(xiàn)了ViewParent接口路克,這個(gè)可以作為View的名義上的父視圖,RootView繼承了Hanld類养交,可以接收事件分發(fā)精算,Android的所有的觸屏事件、按鍵事件碎连、界面刷新事件都是通過ViewRoot來進(jìn)行分發(fā)的灰羽。
他們之間的關(guān)系:
2.DecorView的創(chuàng)建
在Activity中的setContentView();
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
可以看出實(shí)際上是交給交給window裝載視圖。
在attach方法中鱼辙,
@UnsupportedAppUsage
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
····················································
//創(chuàng)建一個(gè)window的對(duì)象
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowControllerCallback(this);
//設(shè)置回調(diào)廉嚼,向Activity分發(fā)點(diǎn)擊或者狀態(tài)變化事件
mWindow.setCallback(this);
··············································
//給Window設(shè)置WindowManager對(duì)象
mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
······················································
}
在Activity中的attach()方法中,生成了PhoneWindow實(shí)例倒戏。
public void setContentView(int layoutResID) {
//mContentParent為空怠噪, 創(chuàng)建一個(gè)DecroView
if (mContentParent == null) {
installDecor();
} else {
//mContentParent不為空, 刪除其中的View
mContentParent.removeAllViews();
}
//為mContentParent添加子View, 即Activity中設(shè)置的布局文件
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//回調(diào)通知杜跷, 內(nèi)容改變
cb.onContentChanged();
}
}
其中的mContentParent指的是布局中的 @android:id/content 所對(duì)應(yīng)的FrameLayout傍念。
上述流程中,大致可以了解先在PhoneWindow中創(chuàng)建了一個(gè)DecroView葛闷,其中創(chuàng)建過程中憋槐,可能根據(jù)Theme不同,加載不同的布局格式淑趾,例如有沒有Title秦陋,有沒有設(shè)置ActionBar等,然后再向mContentParent中中加入View治笨,即Activity中設(shè)置的布局驳概。到此赤嚼,視圖一層層嵌套添加上了。
DecorView的顯示
通過setContentView設(shè)置的界面顺又,為什么在onResum()之后才對(duì)用戶可見更卒?這個(gè)需要從ActivityThread開始說起。
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
//就是在這里調(diào)用了Activity.attach()呀稚照, 接著調(diào)用了Activity.onCreat e() 和Activity.onStart() 生命周期蹂空,
//但是由于只是初始化了mDecor, 添加了布局文件果录, 還沒有把
//mDecor添加到負(fù)責(zé)UI顯示的PhoneWindow中上枕, 所以這時(shí)候?qū)τ脩魜碚f, 是不可見的
Activity a = performLaunchActivity(r, customIntent);
......
if (a != null) {
//這里面執(zhí)行了Activity.onResume()
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotRes umed);
if (!r.activity.mFinished && r.startsNotResumed) {
try {
r.activity.mCalled = false;
//執(zhí)行Activity.onPause()
mInstrumentation.callActivityOnPause(r.activity);
}
}
}
}
主要在handleResumeActivity方法中弱恒,在這其中辨萍,DecorView將會(huì)顯示出來。
handleResumeActivity()方法:
final void handleResumeActivity(IBinder token, boolean clearHide,boolean isForward, boolean reallyResume) {
//這個(gè)時(shí)候返弹, Activity.onResume()已經(jīng)調(diào)用了锈玉, 但是現(xiàn)在界面還是不可見的
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
//decor對(duì)用戶不可見
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
//被添加進(jìn)WindowManager了, 但是這個(gè)時(shí)候义起, 還是不可見的
wm.addView(decor, l);
}
if (!r.activity.mFinished && willBeVisible
&& r.activity.mDecor != null && !r.hideForNow) {
//在這里拉背, 執(zhí)行了重要的操作,使得DecorView可見
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
}
}
}
當(dāng)我們執(zhí)行了Activity.makeVisible();之后,界面才對(duì)我們是可見的默终。
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
//將DecorView添加到WindowManager
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
//DecorView可見
mDecor.setVisibility(View.VISIBLE);
}
到此DecorView便可見椅棺,顯示在屏幕中。但是在這其中齐蔽,wm.addView(mDecor,getWindow().getAttributes()); 起到了重要的作用土陪, 因?yàn)槠鋬?nèi)部創(chuàng)建了一個(gè)ViewRootImpl對(duì)象, 負(fù)責(zé)繪制顯示各個(gè)子View肴熏。
總結(jié)
Activity就像個(gè)控制器, 不負(fù)責(zé)視圖部分顷窒。 Window像個(gè)承載器蛙吏, 裝著內(nèi)部視圖。 DecorView就是個(gè)頂層視圖鞋吉, 是所有View的最外層布局鸦做。ViewRoot像個(gè)連接器, 負(fù)責(zé)溝通谓着, 通過硬件的感知來通知視圖泼诱, 進(jìn)行用戶之間的交互。