Android⾯试题-来说⼀遍View的绘制流程
作为⼀名开发不管你⼏年经验,view的绘制流程熟记于⼼总少不了吧,今天带⼤家⾛⼀遍,也给⾃⼰加深印象。
setContentView是我们⽤来给activity设置我们写的布局界⾯,我们就从这⾥⼊⼿。
Activity#setContentView
1@UnsupportedAppUsage
2 private Window mWindow;
3
4 public Window getWindow() {
5 return mWindow;
6 }
7
制作android软件流程8public void setContentView(@LayoutRes int layoutResID) {
9 getWindow().setContentView(layoutResID);
10 initWindowDecorActionBar();
11 }
12
可以看到,在activity调⽤了mWindow.setContentView⽅法,⽽window是抽象类,所以我们得它的⼦类PhoneWindow
PhoneWindow#setContentView
1@Override
2 public void setContentView(int layoutResID) {
3 if (mContentParent == null) {
4 installDecor();
5 } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
6 veAllViews();
7 }
8
9 if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
10 final Scene newScene = SceneForLayout(mContentParent, layoutResID,
11 getContext());
12 transitionTo(newScene);
13 } else {
14 mLayoutInflater.inflate(layoutResID, mContentParent);
15 }
16 questApplyInsets();
17 final Callback cb = getCallback();
18 if (cb != null && !isDestroyed()) {
19 cb.onContentChanged();
20 }
21 mContentParentExplicitlySet = true;
22 }
⾸先判断mContentParent是否为空,是会调⽤installDecor()⽅法做些初始化⼯作。然后再通过LayoutInflater将布局⽂件加载到mContentParent上⾯去。
PhoneWindow#installDecor
1private DecorView mDecor;
2private ViewGroup mContentParent;
3private ViewGroup mContentRoot;
4
5private void installDecor() {
6 if (mDecor == null) {
7 mDecor = generateDecor(-1);
8 mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
9 mDecor.setIsRootNamespace(true);
10 if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
11 mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
12 }
13 }
14 if (mContentParent == null) {
15 mContentParent = generateLayout(mDecor);
16 mDecor.makeOptionalFitsSystemWindows();
17 //...
18 }
19}
可以看到mDecor是DecorView类对象,⽽DecorView继承⾃FrameLayout,generateDecor()⽅法就是初始化创建⼀个空的FrameLayout,generateLayout(mDecor) ⽤来初始化mContentParent。
PhoneWindow#generateLayout(mDecor)
1protected ViewGroup generateLayout(DecorView decor) {
2 TypedArray a = getWindowStyle();
3 if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
4 requestFeature(FEATURE_NO_TITLE);
5 } else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
6 requestFeature(FEATURE_ACTION_BAR);
7 }
8
9 if (a.getBoolean(R.styleable.Window_windowActionBarOverlay, false)) {
10 requestFeature(FEATURE_ACTION_BAR_OVERLAY);
11 }
12 //...
13 if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
14 layoutResource = R.layout.screen_swipe_dismiss;
15 } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
16 if (mIsFloating) {
17 TypedValue res = new TypedValue();
18 getContext().getTheme().resolveAttribute(
19 R.attr.dialogTitleIconsDecorLayout, res, true);
20 layoutResource = sourceId;
21 } else {
22 layoutResource = R.layout.screen_title_icons;
23 }
24 removeFeature(FEATURE_ACTION_BAR);
25 } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
26 && (features & (1 << FEATURE_ACTION_BAR)) == 0) {
27 layoutResource = R.layout.screen_progress;
28
29 } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {}
30 //...
31 int layoutResource;
32 //...
33 View in = mLayoutInflater.inflate(layoutResource, null);
34 decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
35
36 mContentRoot = (ViewGroup) in;
37
38 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
39 //...
40 return contentParent;
41 }
可以看到,generateLayout()⽅法会根据我们Acivity主题样式,选择加载不同的系统布局资源,并将该视图添加到DecorView中去。
到这⾥只是将布局⽂件绑定到Activity --> mWindow --> DecorView --> mContentParent 上,此时界⾯还未开始绘制。这时我们需要去到关键类ActivityThread类当中了。
ActivityThread#handleResumeActivity
1@Override
2 public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
3 String reason) {
4 //...
5 if (r.window == null && !a.mFinished && willBeVisible) {
6 r.window = Window();
7 View decor = DecorView();
8 decor.setVisibility(View.INVISIBLE);
9 ViewManager wm = a.getWindowManager();
10 WindowManager.LayoutParams l = Attributes();
11 a.mDecor = decor;
12 l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
13 l.softInputMode |= forwardBit;
14 if (r.mPreserveWindow) {
15 a.mWindowAdded = true;
16 r.mPreserveWindow = false;
17 ViewRootImpl impl = ViewRootImpl();
18 if (impl != null) {
19 ifyChildRebuilt();
20 }
21 }
22 //...
23 if (r.activity.mVisibleFromClient) {
24 r.activity.makeVisible();
25 }
26 //...
27 }
可以看到调⽤了 WindowManager.addView()⽅法,⽽WindowManager是⼀个接⼝,也就是调⽤WindowManagerGlobl.addView()⽅法。
WindowManagerGlobl#addView():
1public void addView(View view, ViewGroup.LayoutParams params,
2 Display display, Window parentWindow) {
3 //...
4 root = new Context(), display);
5
6 view.setLayoutParams(wparams);
7
8 mViews.add(view);
9 mRoots.add(root);
10 mParams.add(wparams);
11 }
12
13 // do this last because it fires off messages to start doing things
14 try {
15 root.setView(view, wparams, panelParentView);
16 } catch (RuntimeException e) {
17 // BadTokenException or InvalidDisplayException, clean up.
18 synchronized (mLock) {
19 final int index = findViewLocked(view, false);
20 if (index >= 0) {
21 removeViewLocked(index, true);
22 }
23 }
24 throw e;
25 }
26 }
该⽅法中实例化了 ViewRootImpl,并且调⽤了ViewRootImpl.setView()⽅法来持有当前的DecorView。
ViewRootImpl#setView()
1
2public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
3 synchronized (this) {
4 if (mView == null) {
5 //..
6 requestLayout();
7 //...
8 }
9 }
10}
11
12 @Override
13 public void requestLayout() {
14 if (!mHandlingLayoutInLayoutRequest) {
15 checkThread();
16 mLayoutRequested = true;
17 scheduleTraversals();
18 }
19 }
20
21 //校验所在线程,mThread是在ViewRootImpl初始化的时候执⾏mThread = Thread.currentThread()进⾏赋值的,也就是初始化ViewRootImpl所在的线程。
22 void checkThread() {
23 if (mThread != Thread.currentThread()) {
24 throw new CalledFromWrongThreadException(
25 "Only the original thread that created a view hierarchy can touch its views.");
26 }
27 }
28
29 void scheduleTraversals() {
30 if (!mTraversalScheduled) {
31 mTraversalScheduled = true;
32 mTraversalBarrier = Looper().postSyncBarrier();
33 mChoreographer.postCallback(
34 Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
35 if (!mUnbufferedInputDispatch) {
36 scheduleConsumeBatchedInput();
37 }
38 notifyRendererOfFramePending();
39 }
40 }
41
42 final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
43
44 final class TraversalRunnable implements Runnable {
45 @Override
46 public void run() {
47 doTraversal();
48 }
49 }
50
51 //做任务
52 void doTraversal() {
53 if (mTraversalScheduled) {
54 mTraversalScheduled = false;
55 Looper().removeSyncBarrier(mTraversalBarrier);
56
57 if (mProfile) {
58 Debug.startMethodTracing("ViewAncestor");
59 }
60
61 aceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论