1.前言
- 最近一直在看 《Android進階解密》 的一本書,這本書編寫邏輯嘱巾、流程都非常好憨琳,而且很容易看懂,非常推薦大家去看看(沒有收廣告費旬昭,單純覺得作者寫的很好)篙螟。
- 上一篇簡單的介紹了Android進階(五):Service啟動過程(最詳細&最簡單)。
- 今天就介紹:Activity啟動時View顯示過程 (基于Android 8.0 系統(tǒng))稳懒。
- 文章中實例 linhaojian的Github
2.View顯示過程時序總圖
-
引用下面的時序總圖,方便更容易理解下文源碼部分的內(nèi)容慢味。
3.源碼分析
3.1 ActivityThread
- 從之前分析Android進階(四):Activity啟動過程(最詳細&最簡單)可知场梆,Activtiy在調(diào)用完onResume后,會開始繪制界面纯路,所以就可以從ActivityThread對View顯示過程進行跟蹤或油。
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
// Activity調(diào)用完onResume之后,會真正開始繪制界面
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();//PhoneWindow
View decor = r.window.getDecorView();// 1
decor.setVisibility(View.INVISIBLE);
//Activity中的WindowMangerImp對象驰唬,它實現(xiàn)ViewManager接口
ViewManager wm = a.getWindowManager();//2
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;//把phoneWindow里的DecorView賦值給Activity的decor
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (r.mPreserveWindow) {
a.mWindowAdded = true;
r.mPreserveWindow = false;
ViewRootImpl impl = decor.getViewRootImpl();
if (impl != null) {
impl.notifyChildRebuilt();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//將decor添加在WindowManager(WindowMangerImp)中
wm.addView(decor, l);//3
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}
}
- 注釋1:獲取PhoneWindow中的DecorView,DecorView在Activity調(diào)用setContentView時被創(chuàng)建顶岸;
- 注釋2:獲取ViewManager的實現(xiàn)類WindowMangaerImp,WindowManagerImp在Activity中attach()被創(chuàng)建叫编;
- 注釋3:將DecorView與相關(guān)的布局參數(shù)傳遞至WindowManagerImp中辖佣;
3.2 WindowManagerImpl
public final class WindowManagerImpl implements WindowManager {
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);// 1
}
}
- 注釋1:其實就是運用了外觀模式,真正的實現(xiàn)在WindowManagerGloball的addView()搓逾;
3.3 WindowManagerGlobal
public final class WindowManagerGlobal {
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
//...
root = new ViewRootImpl(view.getContext(), display);// 1
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);// 2
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
- 注釋1:創(chuàng)建ViewRootImpl實例卷谈;
- 注釋2:把decorview傳遞至ViewRootImpl;
3.4 ViewRootImpl
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
// 先把UI界面的數(shù)據(jù)準備好(測量--布局--繪制)
requestLayout();// 1
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();
//將該Window添加到屏幕霞篡。
//mWindowSession實現(xiàn)了IWindowSession接口世蔗,它是Session的客戶端Binderd代理對象.
//addToDisplay是一次AIDL的跨進程通信端逼,通知WindowManagerService添加IWindow
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), mWinFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel);// 2
} catch (RemoteException e) {
//...
} finally {
if (restore) {
attrs.restore();
}
}
}
}
- 注釋1:刷新界面,下文會繼續(xù)介紹污淋;
- 注釋2:**mWindowSession是Session的代理對象顶滩,而Session在WindowManagerService中被初始化,這里通過AIDL的方式與WindowManagerService進行跨進程通訊寸爆。
**礁鲁;
3.5 Session
class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets,
Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outOutsets, outDisplayCutout, outInputChannel);// 1
}
}
- 注釋1:其實就是調(diào)用WindowManagerService的addWindow();
3.6 WindowManagerService
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel) {
//...
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid,
session.mCanAddInternalSystemWindow);// 1
// ...
// 初始化SurfaceSession對象同時會調(diào)用底層相關(guān)內(nèi)容(SurfaceComposerClient,SurfaceComposerClient
// 是與SurfaceFlinger通訊的代理對象)
win.attach();// 2
mWindowMap.put(client.asBinder(), win);
// ....
}
}
- 注釋1:創(chuàng)建表示窗口狀態(tài)的對象而昨,并把相關(guān)信息傳入救氯;
- 注釋2:調(diào)用窗口狀態(tài)對象的初始化函數(shù)
3.7 WindowState
class WindowState extends WindowContainer<WindowState> implements WindowManagerPolicy.WindowState {
void attach() {
if (localLOGV) Slog.v(TAG, "Attaching " + this + " token=" + mToken);
mSession.windowAddedLocked(mAttrs.packageName);//1
}
}
- 注釋1:調(diào)用Session的windowAddedLocked函數(shù);
- Session的windowAddedLocked()
void windowAddedLocked(String packageName) {
mPackageName = packageName;
mRelayoutTag = "relayoutWindow: " + mPackageName;
if (mSurfaceSession == null) {
if (WindowManagerService.localLOGV) Slog.v(
TAG_WM, "First window added to " + this + ", creating SurfaceSession");
mSurfaceSession = new SurfaceSession();// 1
if (SHOW_TRANSACTIONS) Slog.i(
TAG_WM, " NEW SURFACE SESSION " + mSurfaceSession);
mService.mSessions.add(this);
if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
mService.dispatchNewAnimatorScaleLocked(this);
}
}
mNumWindow++;
}
- 注釋1:其實就是初始化SurfaceSession歌憨,SurfaceSession類中大部分都是native的函數(shù)着憨,該類的作用主要是初始化底層庫中的SurfaceComposerClient(與SurfaceFlinger通訊,SurfaceFlinger才是真正實現(xiàn)合成界面并顯示至手機屏幕中)务嫡;
- 到這里甲抖,我們大概知道
ActivityThread.handleResumeActivity()
所引發(fā)的一些操作:- 1.
ActivityThread
通過WindowManagerGlobal
創(chuàng)建ViewRootImpl
(一個Winodw可包含多個ViewRootImpl); - 2.
ViewRootImpl
通過IWindowSession
代理對象最終與WindowManagerService
通訊心铃; - 3.
WindowManagerService
中會為應(yīng)用程序創(chuàng)建一個WindowState
准谚,代表著應(yīng)用程序窗口信息; - 4.
WindowState
中通過Session
創(chuàng)建一個SurfaceSession
(SurfaceSession作用:就是使應(yīng)用程序與Surfacelginer構(gòu)建通訊環(huán)境)去扣;
- 1.
- 下面就開始真正的把繪制內(nèi)容填充至手機屏幕(
Surface
是Window
UI載體柱衔,所以繪制的內(nèi)容最終在應(yīng)用程序端會變成Surface);
3.8 ViewRootImpl的requestLayout()
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
//啟動一個延遲任務(wù)愉棱,任務(wù)內(nèi)容:mTraversalRunnable
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
if (!mUnbufferedInputDispatch) {
scheduleConsumeBatchedInput();
}
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
void doTraversal() {
if (mTraversalScheduled) {
mTraversalScheduled = false;
mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
performTraversals();// 1
if (mProfile) {
Debug.stopMethodTracing();
mProfile = false;
}
}
}
- 注釋1:performTraversals真正的界面繪制過程唆铐;
private void performTraversals() {
//...
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);// 1
//...
performMeasure();
//...
performLayout(lp, mWidth, mHeight);
//...
performDraw();
}
- performTraversals函數(shù)中,包含4個比較重要的方法奔滑,如上述代碼塊中的注釋1-4:
- 注釋1:relayoutWindow函數(shù)會繼續(xù)跟WindowManagerService通訊艾岂,下文會展開他們通訊的作用;
private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
boolean insetsPending) throws RemoteException {
//通過Session的代理對象朋其,調(diào)用其中的relayout函數(shù)王浴,而relayout最終也是調(diào)用WindowManangerService的relayoutWindow函數(shù)
int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame, mPendingDisplayCutout,
mPendingMergedConfiguration, mSurface);// 1
//....
return relayoutResult;
}
- 注釋1:通過Session的代理對象,最終與WindowManangerService通訊梅猿,從傳入的參數(shù)觀看到一個
mSurface
氓辣,而這個就是顯示界面到屏幕的關(guān)鍵,那這個mSurface從哪里創(chuàng)建呢袱蚓?它里面包含什么內(nèi)容筛婉?;
- Surface創(chuàng)建
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
// These can be accessed by any thread, must be protected with a lock.
// Surface can never be reassigned or cleared (use Surface.clear()).
public final Surface mSurface = new Surface();
}
- 從上述代碼可以發(fā)現(xiàn),其實在
ViewRootImpl
創(chuàng)建的同時初始化了一個空殼的Surface
,上述的relayoutWindow函數(shù)把這個空殼Surface傳遞至WindowManangerService具體是干什么爽撒,我們進行跟蹤入蛆。 - WindowManangerService的relayoutWindow函數(shù)
public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
int requestedWidth, int requestedHeight, int viewVisibility, int flags,
long frameNumber, Rect outFrame, Rect outOverscanInsets, Rect outContentInsets,
Rect outVisibleInsets, Rect outStableInsets, Rect outOutsets, Rect outBackdropFrame,
DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
Surface outSurface) {
//...
try {
result = createSurfaceControl(outSurface, result, win, winAnimator);
} catch (Exception e) {
mInputMonitor.updateInputWindowsLw(true /*force*/);
Slog.w(TAG_WM, "Exception thrown when creating surface for client "
+ client + " (" + win.mAttrs.getTitle() + ")",
e);
Binder.restoreCallingIdentity(origId);
return 0;
}
//...
}
//.....
private int createSurfaceControl(Surface outSurface, int result, WindowState win,
WindowStateAnimator winAnimator) {
if (!win.mHasSurface) {
result |= RELAYOUT_RES_SURFACE_CHANGED;
}
WindowSurfaceController surfaceController;
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);// 1
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
if (surfaceController != null) {
surfaceController.getSurface(outSurface); // 2
if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " OUT SURFACE " + outSurface + ": copied");
} else {
// For some reason there isn't a surface. Clear the
// caller's object so they see the same state.
Slog.w(TAG_WM, "Failed to create surface control for " + win);
outSurface.release();
}
return result;
}
- 注釋1:winAnimator.createSurfaceLocked實際上是創(chuàng)建了一個SurfaceControl(SurfaceControl負責(zé)操作與維護Surface);
- 注釋2:就是把SurfaceControl關(guān)聯(lián)至outSurface中硕勿;
- 到這里哨毁,我們大概知道ViewRootImpl.relayoutWindow所觸發(fā)的操作:
- 1.
ViewRootImpl
把Surface
通過Session
的代理對象,最終傳遞至WindowManangerService
源武; - 2.
WindowManangerService
中通過創(chuàng)建WindowSurfaceController
扼褪; - 3.
WindowSurfaceController
中實現(xiàn)Surface
關(guān)聯(lián)SurfaceControl
; - 4.
SurfaceControl
會創(chuàng)建Native層的Surface粱栖,并把指針賦值與ViewRootImpl
的Surface话浇;
- 1.
- 下面繼續(xù)跟蹤View是如何與Surface產(chǎn)生關(guān)聯(lián);
3.8 ViewRootImpl的performDraw()
private void performDraw() {
try {
// 調(diào)用draw繪制界面闹究,最終會調(diào)用drawSoftware()
boolean canUseAsync = draw(fullRedrawNeeded);
if (usingAsyncReport && !canUseAsync) {
mAttachInfo.mThreadedRenderer.setFrameCompleteCallback(null);
usingAsyncReport = false;
}
} finally {
mIsDrawing = false;
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty, Rect surfaceInsets) {
//.....
final Canvas canvas;
//.....
canvas = mSurface.lockCanvas(dirty);// 1
//.....
mView.draw(canvas);// 2
//.....
surface.unlockCanvasAndPost(canvas); // 3
}
- 注釋1:通過Surface獲取Canvas畫布幔崖;
- 注釋2:將畫布傳入至DecorView的draw方法中,并向畫布繪制或者填充內(nèi)容渣淤;
- 注釋3:把繪制完的畫布傳遞至Surface赏寇,最后Surface會調(diào)用相關(guān)的native方法,把界面數(shù)據(jù)添加至底層Buffer中价认,待SurfaceFlinger處理繪制嗅定;
4.關(guān)系鏈
- 綜合源碼分析與上述圖示,可匯總以下信息:
1.ViewRootImpl
通過創(chuàng)建對應(yīng)的Session
用踩、SurfaceSession
渠退,并與SurfaceFlinger
構(gòu)建通訊環(huán)境;
2.WindowManangerService
創(chuàng)建SurfaceController
管理窗口屬性與創(chuàng)建Native層的Surface
,并將Native的Surface
指向ViewRootImpl
的Surface
;
3.ViewRootImpl
中會把View的內(nèi)容傳遞至Surface
中脐彩,最后會把界面數(shù)據(jù)保存至ShareBuffer
碎乃;
4.SurfaceFlinger
接收到ShareBuffer
后,通知相關(guān)硬件進行顯示丁屎;
5.總結(jié)
- 到此荠锭,
Activity啟動時View顯示過程
介紹完畢旱眯。 - 如果喜歡我的分享晨川,可以點擊 關(guān)注 或者 贊,你們支持是我分享的最大動力 删豺。
- linhaojian的Github
歡迎關(guān)注linhaojian_CSDN博客或者linhaojian_簡書共虑!
不定期分享關(guān)于安卓開發(fā)的干貨。
寫技術(shù)文章初心
- 技術(shù)知識積累
- 技術(shù)知識鞏固
- 技術(shù)知識分享
- 技術(shù)知識交流