Activity代碼很簡單,調用getWindow().setContentView(layoutResID),即調用了PhoneWindow的setContent()方法
貼一下PhoneWindow的setContent方法bash
@Override
public void setContentView(int layoutResID) {
//安裝DecorView
if (mContentParent == null) {
installDecor();
}
// ·······省略部分代碼·······
//將設置的layoutResID的佈局放入到 mContentParent中
mLayoutInflater.inflate(layoutResID, mContentParent);
// ·······省略部分代碼·······
}
複製代碼
關鍵方法installDecoride
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
//1.構建DecorView
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
//2.生成mContentParent mContentParent實際是id爲ID_ANDROID_CONTENT的FrameLayout,即要添加布局的父佈局。
mContentParent = generateLayout(mDecor);
final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
R.id.decor_content_parent);
//3.設置Activity標題欄相關
if (decorContentParent != null) {
mDecorContentParent = decorContentParent;
mDecorContentParent.setWindowCallback(getCallback());
if (mDecorContentParent.getTitle() == null) {
mDecorContentParent.setWindowTitle(mTitle);
}
final int localFeatures = getLocalFeatures();
for (int i = 0; i < FEATURE_MAX; i++) {
if ((localFeatures & (1 << i)) != 0) {
mDecorContentParent.initFeature(i);
}
}
mDecorContentParent.setUiOptions(mUiOptions);
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
(mIconRes != 0 && !mDecorContentParent.hasIcon())) {
mDecorContentParent.setIcon(mIconRes);
} else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
mIconRes == 0 && !mDecorContentParent.hasIcon()) {
mDecorContentParent.setIcon(
getContext().getPackageManager().getDefaultActivityIcon());
mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
}
if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
(mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
mDecorContentParent.setLogo(mLogoRes);
}
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) {
invalidatePanelMenu(FEATURE_ACTION_BAR);
}
} else {
mTitleView = findViewById(R.id.title);
if (mTitleView != null) {
if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
final View titleContainer = findViewById(R.id.title_container);
if (titleContainer != null) {
titleContainer.setVisibility(View.GONE);
} else {
mTitleView.setVisibility(View.GONE);
}
mContentParent.setForeground(null);
} else {
mTitleView.setText(mTitle);
}
}
}
//4.設置背景
if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
mDecor.setBackgroundFallback(mBackgroundFallbackResource);
}
// 5.獲取過渡元素相關信息
if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
// ·······省略部分代碼·······
}
}
}
複製代碼
installDecor()主要有四個部分oop
至此,DecoverView構建完成,並將佈局添加入DecoverView中佈局
咱們知道,在Activity生命週期,onStart方法在視圖可見時觸發,那麼DecoverView添加到window確定在onStart方法以前
咱們一步一步往前找會發現
Activity.onStart <- Instrumentation.callActivityOnStart <- Activity.performStart <- Activity.performRestart <- Activity.performResume <- ActivityThread.performResumeActivity <- ActivityThread.handleResumeActivity
咱們從handleResumeActivity分析post
(有興趣的能夠繼續向前查找 Activity.startActivityForResult -> Instrumentation.execStartActivity -> ActivityManagerService.startActivity -> ActivityManagerService.startActivityAsUser -> ActivityStarter.execute -> ActivityStarter.startActivity -> ActivityStarter.startActivityUnchecked-> ActivityStack.ensureActivitiesVisibleLocked -> ActivityStack.makeVisibleAndRestartIfNeeded -> ActivityStackSupervisor.startSpecificActivityLocked -> ActivityStackSupervisor.realStartActivityLocked -> ClientLifecycleManager.scheduleTransaction -> ApplicationThread.scheduleTransaction -> ActivityThread.scheduleTransaction -> Activity.sendMessage(ActivityThread.H.EXECUTE_TRANSACTION, transaction) -> ActivityThread.H.handleMessage case:EXECUTE_TRANSACTION -> TransactionExecutor.execute -> TransactionExecutor.executeLifecycleState -> ResumeActivityItem.execute -> ActivityThread.handleResumeActivity )
動畫
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
// 取消空閒狀態的 GC任務
unscheduleGcIdler();
mSomeActivitiesChanged = true;
// 1.執行Activity的resume方法
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
// ·······省略部分代碼·······
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
// 2.將decorView設置爲INVISIBLE
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
// Normally the ViewRoot sets up callbacks with the Activity
// in addView->ViewRootImpl#setView. If we are instead reusing
// the decor view we have to notify the view root that the
// callbacks may have changed.
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
//3. 將decor添加到WindowManager中
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
// ·······省略部分代碼·······
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
// ·······省略部分代碼·······
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
//4. 設置Activity可見
r.activity.makeVisible();
}
}
r.nextIdle = mNewActivities;
mNewActivities = r;
// 添加空閒任務
Looper.myQueue().addIdleHandler(new Idler());
}
複製代碼
主要包含三部分ui
wm.addView的方法實如今WindowManagerImpl中,而後又調用了代理類WindowManagerGlobal的addView方法,下面看下WindowManagerGlobal.addView方法this
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
// ·······省略部分代碼·······
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
//1. 添加系統屬性更改回調,發送變化時,調用ViewRootImpl的loadSystemProperties方法
if (mSystemPropertyUpdater == null) {
mSystemPropertyUpdater = new Runnable() {
@Override public void run() {
synchronized (mLock) {
for (int i = mRoots.size() - 1; i >= 0; --i) {
mRoots.get(i).loadSystemProperties();
}
}
}
};
SystemProperties.addChangeCallback(mSystemPropertyUpdater);
}
//2.判斷該view是否已被添加,若是被添加過,而且在正在銷燬的列表中,則進行銷燬,不然拋出非法狀態異常
int index = findViewLocked(view, false);
if (index >= 0) {
if (mDyingViews.contains(view)) {
mRoots.get(index).doDie();
} else {
throw new IllegalStateException("View " + view
+ " has already been added to the window manager.");
}
}
// ·······省略部分代碼·······
//3.建立ViewRootImpl對象
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// 4.調用ViewRootImpl的setView方法
try {
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
複製代碼
主要有四步:spa
從ViewParent註釋能夠看出,視圖的頂部,協調View和WindowManager,不少程度上實現了WindowManagerGlobal的細節。
咱們從setView開始看線程
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
//向DisplayManager註冊顯示屏監聽器 能夠監聽到顯示屏的打開和關閉
mAttachInfo.mDisplayState = mDisplay.getState();
mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
// 手機反饋事件處理
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
// ·······省略部分代碼·······
//建立mSurfaceHolder
if (view instanceof RootViewSurfaceTaker) {
mSurfaceHolderCallback =
((RootViewSurfaceTaker)view).willYouTakeTheSurface();
if (mSurfaceHolderCallback != null) {
mSurfaceHolder = new TakenSurfaceHolder();
mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
mSurfaceHolder.addCallback(mSurfaceHolderCallback);
}
}
// ·······省略部分代碼·······
// 1. 在添加到windowManager以前 安排一次佈局 ,以確保咱們在從系統接收任何其餘事件以前進行從新佈局。
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
// 2.經過IPC將window添加入WindowSeession進行顯示
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);
}
// ·······省略部分代碼·······
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
// 3. 建立窗口輸入事件接收器,並設置輸入管道流
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
// 4. 將ViewRootImpl綁定爲DecorView的Parent
view.assignParent(this);
// ·······省略部分代碼·······
// 5. 經過責任鏈模式處理輸入階段 主要針對觸摸事件和物理按鍵事件
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
}
}
}
複製代碼
把代碼主要分爲了五步
看下requestLayout方法
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
複製代碼
代碼很簡單,檢查線程,執行scheduleTraversals 檢查線程會判斷當前線程是否爲UI線程,若是不是UI線程,則拋出異常,這裏就是爲何子線程不能更新UI的緣由。
可是子線程真的不能更新UI嗎?從上面分析咱們能夠看出,當在wm.addView時,纔會建立的ViewRootImpl,而wm.addView,是在onResume時執行,因此若是在onResume執行前,是能夠在子線程更新UI。(其實這個時候視圖並無被添加到view中)
接下來看下scheduleTraversals方法
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
// 1.在MessageQueue中添加同步柵欄
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 2.由編舞者處理 佈局和繪製
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
// 3.通知渲染層將有新的幀
notifyRendererOfFramePending();
// 若是須要釋放繪製鎖
pokeDrawLockIfNeeded();
}
}
複製代碼
mChoreographer.postCallback方法的內部的調用鏈
postCallback -> postCallbackDelayed -> postCallbackDelayedInternal -> scheduleFrameLocked -> doFrame(System.nanoTime(), 0) -> doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos)
最終會調用上一部傳入的mTraversalRunnable的run方法 mTraversalRunnable.run -> doTraversal -> performTraversals performTraversals方法是主要的繪製方法。performTraversals會依次執行 performMeasure -> performLayout -> performDraw 完成視圖的幀繪製