Activity啟動過程中做了哪些事情?下面的時序圖展示裡啟動過程中函數的調用過程, 從圖中可以知道大概流程。

在介紹細節的時候是從上往下函數調用過程介紹的,如果不知道某個函數是在哪裡被誰調用的,可以回過頭來看下時序圖。下面是對一些細節進行介紹。
1. 在Android中有兩種操作會引發Activity的啟動,一種使用者點選Launcher的應用程式圖示時,Launcher會為啟動應用程式的主Activity。另外一種是在已經起來的Activity内部通過調用startActvity接口啟動新的Activity。每一個Activity都可以在内部啟動新的Activity。圖中就是從一個Activity調用startActivity啟動另外一個Activity開始。
Activity.startActivity()
public void startActivity(Intent intent, Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
startActivity()中調用攜帶requestCode參數的startActivityForResult()啟動新的activity。
Activity. startActivityForResult()
public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
//一般的Activity的mParent為null
if (mParent == null) {
//調用Instrumentation.execStartActivity()啟動新的Activity。
//mMainThread類型為ActivityThread, 在attach()函數被回調時被指派。
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options);
if (ar != null) {
// 如果activity之前已經啟動,而且處于阻塞狀态,
//execStartActivity函數直接傳回要啟動的activity的result或者null。
//(注意:這就是Activity.onActivityResult()會在啟動
//另外一個activity啟動時被回調的原因。
// 若result非空,發送結果給本activity,即onActivityResult會被調用。
mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// 如果這次啟動需要被啟動的activity傳回一個結果,
// 則在收到傳回結果前,本activity保持不可見。
mStartedActivity = true;
}
final View decor = mWindow != null ? mWindow.peekDecorView() : null;
if (decor != null) {
decor.cancelPendingInputEvents();
}
// TODO Consider clearing/flushing other event sources and events for child windows.
} else {
//在ActivityGroup内部的Activity調用startActivity的時候會走到這裡,
//内部處理邏輯和上面是類似的
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else {
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
Instrumentation類的功能是輔助Activity的監控和測試,接着看execStartActivity()函數的實作。
Instrumentation.execStartActivity()
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
//将contextThread轉成ApplicationThread.
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
synchronized (mSync) {
//檢查是否存在這個activity
final int N = mActivityMonitors.size();
for (int i=0; i<N; i++) {
final ActivityMonitor am = mActivityMonitors.get(i);
if (am.match(who, null, intent)) {
am.mHits++;
if (am.isBlocking()) { //若找到,而且處于阻塞狀态,直接傳回。
return requestCode >= 0 ? am.getResult() : null;
}
break;
}
}
}
}
try {
intent.migrateExtraStreamToClipData(); //轉移資料
intent.prepareToLeaveProcess(); //準備讓intent離開一個app程序
//通過AcitivityManagerNative與ActivityManagerService關聯起來,
//兩個類的關系如下圖,由ActivityManagerService去執行實際動作。
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, null, options);
//檢查啟動結果,如果無法打開activity,
//則抛出諸如ActivityNotFoundException類似的各種異常
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
}
return null;
}
2. ActivityManager的功能是與系統中所有運作着的Activity互動提供了接口,主要的接口圍繞着運作中的程序資訊,任務資訊,服務資訊等,它的大多數功能都是調用了ActivityManagerNative類接口來完成的。
ActivityManager相關靜态類圖如下圖,可以看出這是典型的Proxy模式:
結合面的類結構圖,其中ActivityManager是一個用戶端,為了減少ActivityManager與ActivityManagerService的耦合度,在這中間使用了ActivityManagerNative類,該類内部使用ActivityManagerProxy代理類,所有對 ActivityManagerService的通路都轉換成對代理類的通路,這樣ActivityManager就與ActivityManagerService解耦了。
為了讓代理類與被代理類保持一緻的接口,由IActivityManager作為ActivityManagerProxy和ActivityManagerNative的公共接口,ActivityManagerService繼承于ActivityManagerNative,也具有相同的接口。
圖中綠色的部分是在SDK中開放給應用程式開發人員的接口,藍色的部分是Proxy模式的實作,紅色的部分是底層的服務實作,是真正的動作執行者。
3 ActivityManagerService. startActivity()
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags,
String profileFile, ParcelFileDescriptor profileFd, Bundle options) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profileFile, profileFd, options, UserHandle.getCallingUserId());
}
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags,
String profileFile, ParcelFileDescriptor profileFd, Bundle options, int userId) {
enforceNotIsolatedCaller("startActivity");
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
false, true, "startActivity", null);
// TODO: Switch to user app stacks here.
return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profileFile, profileFd,
null, null, options, userId);
}
類ActivityStackSupervisor是用來輔助ActivityManagerService對Activity和Task的管理的。其中用ActivityStackSupervisor類來進行對Task的操作,用ActivityStack對Acitivity進行操作。
4. 調用mStackSupervisor.startActivityMayWait()函數後,會執行下面幾個函數,調用關系參照時序圖,函數裡涉及很多細節,這裡隻簡單描述下它們的主要功能:
調用9. ActivityStackSupervisor.startActivityLocked(): 檢查啟動權限,建立新的ActivityRecord。
調用10. ActivityStackSupervisor.startActivityUncheckedLocked():處理intent攜帶的launch flags, launchMode。(後面再研究launch相關的flag和mode)
調用11. ActivityStack.startActivityLocked():将activity放到所屬task的頂部,重置Task(resetTaskIfNeededLocked),調用WindowManager.setAppStartingWindow()。
調用13. ActivityStackSupervisor.resumeTopActivitiesLocked():判斷ActivityStack數組中是否存在target ActivityStack。
調用14. ActivityStack.resumeTopActivityLocked(): 從目前activity切換到要啟動的activity。
調用15. ActivityStackSupervisor.startSpecificActivityLocked():擷取ProcessRecord(若要啟動的activity的應用已經在運作),若擷取ProcessRecord存在則調用realStartActivityLocked(),否則調用 ActivityManagerServices.startProcessLocked()建立新的ProcessRecord,最後調用Process.start()啟動新的程序(最終調用Zygote啟動新的程序,為了避免混淆,這部分在時序圖中沒有展現,後面再研究)。
調用16. ActivityStackSupervisor.realStartActivityLocked(): 調用mWindowManager.setAppVisibility()設定app可見。
調用19. ActivityThread.scheduleLauncherActivity(): 發送Message LAUNCH_ACTIVITY給Handler.
5. Handler接收到message後,執行ActivityThread.handleLaunchActivity()。
ActivityThread.handleLaunchActivity()
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
......
Activity a = performLaunchActivity(r, customIntent); // 傳回一個activity.
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed);
if (!r.activity.mFinished && r.startsNotResumed) {
// 當這個activity沒有finished而且沒有處于resumed狀态時,
//Acivity Manager實際上想要這個activity以paused狀态開始,
//因為它需要可見,但是又不在前台。
// 為此,需要經過正常啟動(因為activity希望在它們的window被顯示前,
//它們第一次運作時通過onResume),然後暫停它。
//The activity manager actually wants this one to start out
//然而,在這種情況下,不需要走完整的暫停周期(比如freezing等),
//因為activity假定它可以剛好保留它目前的所有狀态。
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
......
} catch (SuperNotCalledException e) {
......
} catch (Exception e) {
......
}
r.paused = true;
}
} else {
......
}
}
6.進一步看performLaunchActivity(),這個函數做了幾件重要的事情:建立activity執行個體,調用Activity.attach()設定參數,觸發Activity.onCreate()。
ActivityThread.performLaunchActivity()
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) { // 填充package info
r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
Context.CONTEXT_INCLUDE_CODE);
}
ComponentName component = r.intent.getComponent();
if (component == null) {
component = r.intent.resolveActivity(mInitialApplication.getPackageManager());
r.intent.setComponent(component); //設定Component
}
if (r.activityInfo.targetActivity != null) {
component = new ComponentName(r.activityInfo.packageName,
r.activityInfo.targetActivity);
}
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); // 根據Activity的類名,通過Java反射機制建立對應的Activity.
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
......
}
try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (activity != null) {
// Activity中getContext()函數傳回的就是這個對象。
Context appContext = createBaseContextForActivity(r, activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
......
// 将Context,ActivityThread,Instrumentation,Application等設定給建立的Activity,供activity使用。
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config);
if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();
if (theme != 0) {
activity.setTheme(theme); // 設定theme
}
activity.mCalled = false;
mInstrumentation.callActivityOnCreate(activity, r.state); // 這個函數會使Activity的onCreate()函數被調用
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart(); // 這個函數會使Activity的onStart()函數被調用
r.stopped = false;
}
if (!r.activity.mFinished) {
if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
mInstrumentation.callActivityOnPostCreate(activity, r.state);
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onPostCreate()");
}
}
}
r.paused = true;
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
......
} catch (Exception e) {
......
}
return activity;
}
7.下面分析下Activity.attach()函數,它建立window對象,設定window manager。
Activity.attach()
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) {
attachBaseContext(context); // 把context指派給父類的mBase成員
mFragments.attachActivity(this, mContainer, null);
mWindow = PolicyManager.makeNewWindow(this); // 調用PolicyManager的函數建立Window對象。
mWindow.setCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode); //設定輸入法mode
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();
// 指派給Acitivity的各個成員
mMainThread = aThread; //mMainThread實際上為ActivityThread。
mInstrumentation = instr;
mToken = token;
mIdent = ident;
mApplication = application;
mIntent = intent;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
// 建立WindowManager對象并設定給window,供window使用.
mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager(); // 儲存WindowManager對象.
mCurrentConfig = config;
}
8. 其中一個關鍵的函數PolicyManager.makeNewWindow()傳回Window對象,實際上是一個PhoneWindow對象。
具體建立過程參考下面代碼:
PolicyManager.PolicyManager
public final class PolicyManager {
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy; // sPolicy為單例的IPolicy對象。
static {
// Pull in the actual implementation of the policy at run-time
try {
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance(); // 建立Policy對象。
} catch (ClassNotFoundException ex) {
......
}
}
// Cannot instantiate this class
private PolicyManager() {}
// The static methods to spawn new policy-specific objects
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context); //通過Policy對象的makeNewWindow建立一個Window。
}
......
}
[email protected]
public class Policy implements IPolicy {
private static final String TAG = "PhonePolicy";
private static final String[] preload_classes = {
"com.android.internal.policy.impl.PhoneLayoutInflater",
"com.android.internal.policy.impl.PhoneWindow",
"com.android.internal.policy.impl.PhoneWindow$1",
"com.android.internal.policy.impl.PhoneWindow$DialogMenuCallback",
"com.android.internal.policy.impl.PhoneWindow$DecorView",
"com.android.internal.policy.impl.PhoneWindow$PanelFeatureState",
"com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState",
};
static {
// For performance reasons, preload some policy specific classes when
// the policy gets loaded.
for (String s : preload_classes) { // 加載所有的類
try {
Class.forName(s);
} catch (ClassNotFoundException ex) {
......
}
}
}
public Window makeNewWindow(Context context) {
return new PhoneWindow(context); // 實際傳回的PhoneWindow對象。
}
......
}
9. setWindowManager()@Window.java
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); // 建立一個WindowManagerImpl對象
}
到這裡可以看到,Activity成員變量mWindow實際上是PhoneWindow類型, 變量mWindowManager實際上是WindowManagerImpl。這
10. Acitivity.attach()函數被調用之後,performLaunchActivity還會觸發Activity.onCreate()函數被調用,在這個函數中會調用setContentView()函數設定Activity的UI内容。
setContentView()有三種實作,它們的功能基本一緻,都是将view添加到mContentParent中:
setContentView()@Activity.java
// 通過一個布局資源設定activity的内容。
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initActionBar();
}
// 直接将View作為内容直接設定到activity的視圖層次中。這種方式設定給view的layoutparams将不起作用,預設為MATCH_PARENT.
public void setContentView(View view) {
getWindow().setContentView(view);
initActionBar();
}
// 設定activity的内容為view, 并設定view的LayoutParams.
public void setContentView(View view, ViewGroup.LayoutParams params) {
getWindow().setContentView(view, params);
initActionBar();
}
下面給出其中一種實作:
setContentView()@PhoneWindow.java
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor(); // 初始化DecorView和mContentParent.
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
installDecor()@PhoneWindow.java
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
......
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
mTitleView = (TextView)findViewById(com.android.internal.R.id.title); // 建立标題欄
......
}
}
generateDecor()@PhoneWindow.java
protected DecorView generateDecor() {
return new DecorView(getContext(), -1); // DecorView從FrameLayout派生,同時實作RootViewSurfaceTaker接口。
}
generateLayout()@PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
......
// Inflate the window decor.
int layoutResource; // 根據情況擷取相應的标題欄資源ID。
int features = getLocalFeatures();
if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
......
layoutResource = res.resourceId;
}
......
}
mDecor.startChanging();
View in = mLayoutInflater.inflate(layoutResource, null); //inflate 标題欄
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); // 加入标題欄
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); // ID_ANDROID_CONTENT:xml布局檔案中main layout的ID, 實際上是mDecorView的一部分。
......
mDecor.finishChanging();
return contentParent;
}
findViewById()@Window.java
public View findViewById(int id) {
return getDecorView().findViewById(id);
}
通過上面的代碼可以看到,在Activity.onCreate()函數裡調用setContentView設定的View,實際上會作為DecorView的子view。DecorView還處理了标題欄顯示等工作。
addView()@ViewGroup.java
public void addView(View child, int index, LayoutParams params) {
// addViewInner()函數中設定LayoutParams時會調用child.requestLayout(),在這裡調用,為了在這裡阻塞child的request.
requestLayout();
invalidate(true); //在下一篇文章中會介紹這個函數
addViewInner(child, index, params, false);
}
11. 我們接着看handleLaunchActivity()中的handleResumeActivity()函數,
handleResumeActivity()@ActivityThread.java
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {
......
ActivityClientRecord r = performResumeActivity(token, clearHide); //會調用到Activity.onResume().
if (r != null) {
final Activity a = r.activity;
final int forwardBit = isForward ? WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
// If the window hasn't yet been added to the window manager,
// and this guy didn't finish itself or start another activity,
// then go ahead and add the window.
// 若這個activity的window沒有加到window manager中,而且它沒有自己finish或者啟動另外一個acitivity,那就繼續,添加這個window.
boolean willBeVisible = !a.mStartedActivity;
if (!willBeVisible) {
try {
willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(a.getActivityToken());
} catch (RemoteException e) {
}
}
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow(); // 獲得在attach()函數中建立出來的window對象。
View decor = r.window.getDecorView(); // 獲得一個View對象
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager(); // 獲得ViewManager對象
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l); // 添加View對象到WindowManager中。
}
} else if (!willBeVisible) { // 如果window已經被添加了,但在resume時啟動另外的activity,這個window将隐藏。
r.hideForNow = true;
}
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r);
// 如果window添加了,執行到這的時候就可見了。
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
if (r.newConfig != null) {
performConfigurationChanged(r.activity, r.newConfig);
freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.newConfig));
r.newConfig = null;
}
WindowManager.LayoutParams l = r.window.getAttributes();
if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != forwardBit) {
l.softInputMode = (l.softInputMode
& (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
| forwardBit;
if (r.activity.mVisibleFromClient) {
ViewManager wm = a.getWindowManager();
View decor = r.window.getDecorView();
wm.updateViewLayout(decor, l); // 根據輸入法顯示模式調整winddow layout。
}
}
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
if (!r.onlyLocalRequest) {
r.nextIdle = mNewActivities;
mNewActivities = r;
Looper.myQueue().addIdleHandler(new Idler());
}
r.onlyLocalRequest = false;
// Tell the activity manager we have resumed.
if (reallyResume) {
try {
ActivityManagerNative.getDefault().activityResumed(token);
} catch (RemoteException ex) {
}
}
} else {
// If an exception was thrown when trying to resume, then just end this activity.
// 如果resume過程出現異常,就finish這個activity.
try {
ActivityManagerNative.getDefault().finishActivity(token, Activity.RESULT_CANCELED, null);
} catch (RemoteException ex) {
}
}
}
addView()@WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
......
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
......
root = new ViewRootImpl(view.getContext(), display); // 建立ViewRootImpl對象
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try {
root.setView(view, wparams, panelParentView); // setView()内調用requestLayout(). 在被加到WindowManager之前排程第一次layout,確定收到系統事件之前重新進行了布局。
} catch (RuntimeException e) {
......
}
}
ViewRootImpl及setView()涉及到了UI繪制。