本文從Activity 創(chuàng)建view闸拿,到View的繪制全過程邮绿,最終呈現(xiàn)在Activity做一個比較全面的梳理。
1. View在Activity上創(chuàng)建
這里要提到有關(guān)Activiy、Window、WindowManager等的相關(guān)知識瞧预。
ActivityThread 的performLaunchActivity是啟動一個Activity的入口,此方法會創(chuàng)建一個Activity仅政。
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
//1. 通過反射創(chuàng)建一個acitiviy
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
...
}
try {
...
//2. 創(chuàng)建window 對象
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window);
...
//3. 調(diào)用ActivityOncreate方法
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
return activity;
}
在Activity的attach中創(chuàng)建相應(yīng)的PhoneWindow對象垢油,并設(shè)置回調(diào)(詳見PhoneWindow中Callback接口),此時Activity持有該Window對象
final void attach(Context context, ActivityThread aThread,
Instrumentation instr,...) {
mWindow = new PhoneWindow(this, window);
mWindow.setWindowControllerCallback(this);
mWindow.setCallback(this);
}
當(dāng)我們在Activity的setContentView方法調(diào)用了Window的setContentView ,
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
實際上調(diào)用了Window的setContentView
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//1. 構(gòu)建Decor
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
// 2. 將布局inflate到mContentParent上
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//3. 回調(diào)給Activity
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
mContentParent相當(dāng)于是DecorView的一部分圆丹,用來繪制content的部分
private void installDecor() {
...
mContentParent = generateLayout(mDecor);
...
}
protected ViewGroup generateLayout(DecorView decor) {
//其中ID_ANDROID_CONTENT 即com.android.internal.R.id.content
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
return contentParent
}
至此View被添加到頂級View, DecorView上滩愁,并顯示在Activity的Window上了。
在ActivityThread的handleResumeActivity接口里:
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
...
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
// ViewManager的實現(xiàn)ViewManagerImpl 調(diào)用WindowManagerGlobal(WindowManager的實現(xiàn))將DecorView添加到
wm.addView(decor, l);
}
WindowManagerGlobal的addview會
...
root = new ViewRootImpl(view.getContext(), display);
...
root.setView(view, wparams, panelParentView);
其實ViewRootImpl的mView就是頂級View:Decoview 辫封。
至此View被添加DecorView上并進(jìn)入繪制流程硝枉。
2. View的繪制流程
在調(diào)用ViewRootImpl的setView中會執(zhí)行其requestLayout方法
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
}
...
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
//在添加到windowMaganer之前首次執(zhí)行l(wèi)ayout
requestLayout();
}
}
requestLayout會依次調(diào)用scheduleTraversals->doTraversal->performTraversals并最終進(jìn)入繪制流程廉丽。
performTraversals會依次調(diào)用performMeasure,performDraw, performLayout,并相應(yīng)的執(zhí)行mView(DecorView)的measure妻味,draw, layout,
到此view的繪制告一段落了正压。后面會繼續(xù)講到一些view繪制的詳細(xì)內(nèi)容