Android 30
更新時間:2021-12-18
文章目錄
- View的繪制流程
- 1) ActivityThread#handleResumeActivity
- 1.1) ActivityThread#performResumeActivity
- 1.1.1) Activity#performResume
- 1.1.1.1) Instrumentation#callActivityOnResume
- 1.2) ViewManager
- 1.2.1) Activity#getWindowManager
- 1.2.1.1) Activity#attach
- 1.2.1.1.1) Window#getWindowManager
- 1.2.1.1.1.1) Window#setWindowManager
- 1.3) ViewManager#addView
- 1.3.1) WindowManagerImpl#addView
- 1.3.1.1) WindowManagerGlobal#addView
- 1.3.1.1.1) ViewRootImpl#setView
- 1.3.1.1.1.1) ViewRootImpl#requestLayout
- 1.3.1.1.1.1.1) ViewRootImpl#scheduleTraversals
- 1.3.1.1.1.1.1.1) ViewRootImpl#doTraversal
- 1.3.1.1.1.1.1.1.1) ViewRootImpl#performTraversals
- 1.3.1.1.1.1.1.1.1.1) ViewRootImpl#measureHierarchy
- 1.3.1.1.1.1.1.1.1.2) ViewRootImpl#performMeasure
- 1.3.1.1.1.1.1.1.1.2.1) View#measure
- 1.3.1.1.1.1.1.1.1.3) ViewRootImpl#performLayout
- 1.3.1.1.1.1.1.1.1.4) ViewRootImpl#performDraw
View的繪制流程

1) ActivityThread#handleResumeActivity
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward, String reason) {
// Activity物件持有者
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
// 獲取到Activity
final Activity a = r.activity;
// 獲取到PhoneWindow
r.window = r.activity.getWindow();
// 獲取到DecorView
View decor = r.window.getDecorView();
// 設定DecorView不可見
decor.setVisibility(View.INVISIBLE);
// 獲取到WindowManager
ViewManager wm = a.getWindowManager();
// 獲取到PhoneWindow的布局屬性
WindowManager.LayoutParams l = r.window.getAttributes();
// 將 DecorView 添加到 ViewManager
wm.addView(decor, l);
}
1.1) ActivityThread#performResumeActivity
來看下 performResumeActivity() 方法里面的內容:
里面呼叫了Activity的performResume方法
public ActivityClientRecord performResumeActivity(IBinder token, boolean finalStateRequest, String reason) {
final ActivityClientRecord r = mActivities.get(token);
r.activity.performResume(r.startsNotResumed, reason);
}
1.1.1) Activity#performResume
再看下 r.activity.performResume(r.startsNotResumed, reason); 的內容:
這里又呼叫了 callActivityOnResume方法
final void performResume(boolean followedByPause, String reason) {
mInstrumentation.callActivityOnResume(this);
}
1.1.1.1) Instrumentation#callActivityOnResume
再往 mInstrumentation.callActivityOnResume(this); 看:
最后會呼叫 onResume() 方法
public void callActivityOnResume(Activity activity) {
activity.onResume();
}
1.2) ViewManager
ViewManager wm = a.getWindowManager();
ViewManager 是一個介面,WindowManager 會繼承它
public interface ViewManager {
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}
1.2.1) Activity#getWindowManager
WindowManager 繼承 ViewManager,通過getWindowManager方法,回傳了mWindowManager,那 mWindowManager在哪賦值的呢?
public WindowManager getWindowManager() {
return mWindowManager;
}
1.2.1.1) Activity#attach
mWindowManager 會在 attach中進行賦值,這里呼叫的是mWindow.getWindowManager() ,再往里面看
final void attach(...) {
// 創建 PhoneWindow 物件
mWindow = new PhoneWindow(this, window, activityConfigCallback);
// 獲取 WindowManager
mWindowManager = mWindow.getWindowManager();
}
1.2.1.1.1) Window#getWindowManager
會回傳 mWindowManager,再去看 它是什么時候被賦值的
public WindowManager getWindowManager() {
return mWindowManager;
}
1.2.1.1.1.1) Window#setWindowManager
mWindowManager 在什么時候被賦值的呢,是在 setWindowManager 方法中,從 WindowManagerImpl拿到的;
另外,WindowManagerImpl 是 WindowManager 的實作類;
ViewManager wm = a.getWindowManager(); 是 從 WindowManagerImpl 拿到的;
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated;
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
1.3) ViewManager#addView
wm 為 ViewManager;
WindowManager 繼承 ViewManager;
WindowManagerImpl 是 WindowManager 的實作類;
那 wm.addView(decor, l); 也就是 呼叫的 WindowManagerImpl 的 addView方法;
1.3.1) WindowManagerImpl#addView
來看下 WindowManagerImpl 的 addView 方法:
是呼叫了 WindowManagerGlobal 的 addView 方法
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
// WindowManagerGlobal mGlobal
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
1.3.1.1) WindowManagerGlobal#addView
WindowManagerGlobal 是管理整個行程,所有的視窗資訊的;
看下它的 addView方法內容
public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow, int userId) {
ViewRootImpl root;
// 創建 ViewRootImpl 物件
root = new ViewRootImpl(view.getContext(), display);
mViews.add(view); // DecorView
mRoots.add(root); // ViewRoomImpl
mParams.add(wparams); // WindowManager.LayoutParams
// DecorView 和 ViewRootImpl 關聯
root.setView(view, wparams, panelParentView, userId);
}
1.3.1.1.1) ViewRootImpl#setView
ViewRootImpl 是 操作自己的視窗
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {
mView = view;
// 請求遍歷
requestLayout();
// 將視窗添加到 WindowManagerService 上
res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
mTempInsets, mTempControls);
view.assignParent(this);
}
1.3.1.1.1.1) ViewRootImpl#requestLayout
進行請求遍歷操作
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread(); // 執行緒檢查
mLayoutRequested = true;
scheduleTraversals(); // 主要看這個
}
}
// 檢查當前執行緒
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
public ViewRootImpl(Context context, Display display, IWindowSession session, boolean useSfChoreographer) {
mThread = Thread.currentThread();
}
1.3.1.1.1.1.1) ViewRootImpl#scheduleTraversals
在 scheduleTraversals 中得 postCallback中有一個mTraversalRunnable,可以看到它最終呼叫 doTraversal 方法;
@UnsupportedAppUsage
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
// 看這個 mTraversalRunnable
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
final class TraversalRunnable implements Runnable {
@Override
public void run() {
doTraversal();
}
}
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
1.3.1.1.1.1.1.1) ViewRootImpl#doTraversal
performTraversals 是 繪制開始的地方
void doTraversal() {
performTraversals();
}
1.3.1.1.1.1.1.1.1) ViewRootImpl#performTraversals
在 performTraversals 中,會進行預測量,測量,布局,繪制等操作;
private void performTraversals() {
boolean windowSizeMayChange = false;
// 預測量
windowSizeMayChange |= measureHierarchy(host, lp, res, desiredWindowWidth, desiredWindowHeight);
// 布局視窗
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
// 測量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
// 布局
performLayout(lp, mWidth, mHeight);
// 繪制
performDraw();
}
1.3.1.1.1.1.1.1.1.1) ViewRootImpl#measureHierarchy
預測量,會進行三次
private boolean measureHierarchy(final View host, final WindowManager.LayoutParams lp,
final Resources res, final int desiredWindowWidth, final int desiredWindowHeight) {
boolean goodMeasure = false;
if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT) {
res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
if (baseSize != 0 && desiredWindowWidth > baseSize) {
childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
// 第一次測量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
goodMeasure = true;
} else {
// 第二次測量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) {
if (DEBUG_DIALOG) Log.v(mTag, "Good!");
goodMeasure = true;
}
}
}
}
if (!goodMeasure) {
childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
// 第三次測量
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()) {
windowSizeMayChange = true;
}
}
}
1.3.1.1.1.1.1.1.1.2) ViewRootImpl#performMeasure
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
if (mView == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
// 測量
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
1.3.1.1.1.1.1.1.1.2.1) View#measure
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
onMeasure(widthMeasureSpec, heightMeasureSpec);
}
// 當自己重寫 onMeasure 的時候,需要呼叫setMeasuredDimension,否則會拋出例外
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
1.3.1.1.1.1.1.1.1.3) ViewRootImpl#performLayout
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, int desiredWindowHeight) {
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
}
1.3.1.1.1.1.1.1.1.4) ViewRootImpl#performDraw
private void performDraw() {
boolean canUseAsync = draw(fullRedrawNeeded);
}
Android setContentView流程:https://blog.csdn.net/yan13507001470/article/details/121588583
請多指教,
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/386630.html
標籤:其他
上一篇:【Android 逆向】ART 函式抽取加殼 ( ART 下的函式抽取恢復時機 | 禁用 dex2oat 機制原始碼分析 )
