Activity的ViewRoot的创建过程(一)

page1
当一个Activity第一次激活的时候会为该Activity组件创建一个ViewRoot对象, 并且与该Activity所创建的应用程序窗口关联起来, 这样就可以通过该ViewRoot对象来控制应用程序窗口视图的UI展示了.
我们从ActivityThread的handleResumeActivity函数开始分析ViewRoot的创建过程, handleResumeActivity函数定义如下, 我们只关心ViewRoot创建的部门:
1     final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
2             boolean reallyResume) {
3         // If we are getting ready to gc after going to the background, well
4         // we are back active so skip it.
5         unscheduleGcIdler();
6
7         ActivityClientRecord r = performResumeActivity(token, clearHide);
8
9         if (r != null) {
10             final Activity a = r.activity;
11
12             if (localLOGV) Slog.v(
13                 TAG, "Resume " + r + " started activity: " +
14                 a.mStartedActivity + ", hideForNow: " + r.hideForNow
15                 + ", finished: " + a.mFinished);
16
17             final int forwardBit = isForward ?
18                     WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
19
20             // If the window hasn't yet been added to the window manager,
21             // and this guy didn't finish itself or start another activity,
22             // then go ahead and add the window.
23             boolean willBeVisible = !a.mStartedActivity;
24             if (!willBeVisible) {
25                 try {
26                     willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
27                             a.getActivityToken());
28                 } catch (RemoteException e) {
29                 }
30             }
31             if (r.window == null && !a.mFinished && willBeVisible) {
32                 r.window = r.activity.getWindow();
33                 View decor = r.window.getDecorView();
34                 decor.setVisibility(View.INVISIBLE);
35                 ViewManager wm = a.getWindowManager();
36                 WindowManager.LayoutParams l = r.window.getAttributes();
37                 a.mDecor = decor;
38                 l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
39                 l.softInputMode |= forwardBit;
40                 if (a.mVisibleFromClient) {
41                     a.mWindowAdded = true;
42                     wm.addView(decor, l);
43                 }
44
45             // If the window has already been added, but during resume
46             // we started another activity, then don't yet make the
47             // window visible.
48             } else if (!willBeVisible) {
49                 if (localLOGV) Slog.v(
50                     TAG, "Launch " + r + " mStartedActivity set");
51                 r.hideForNow = true;
52             }
53
54             // Get rid of anything left hanging around.
55             cleanUpPendingRemoveWindows(r);
56
57             // The window is now visible if it has been added, we are not
58             // simply finishing, and we are not starting another activity.
59             if (!r.activity.mFinished && willBeVisible
60                     && r.activity.mDecor != null && !r.hideForNow) {
61                 if (r.newConfig != null) {
62                     if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
63                             + r.activityInfo.name + " with newConfig " + r.newConfig);
64                     performConfigurationChanged(r.activity, r.newConfig);
65                     freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.newConfig));
66                     r.newConfig = null;
67                 }
68                 if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
69                         + isForward);
70                 WindowManager.LayoutParams l = r.window.getAttributes();
71                 if ((l.softInputMode
72                         & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
73                         != forwardBit) {
74                     l.softInputMode = (l.softInputMode
75                             & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
76                             | forwardBit;
77                     if (r.activity.mVisibleFromClient) {
78                         ViewManager wm = a.getWindowManager();
79                         View decor = r.window.getDecorView();
80                         wm.updateViewLayout(decor, l);
81                     }
82                 }
83                 r.activity.mVisibleFromServer = true;
84                 mNumVisibleActivities++;
85                 if (r.activity.mVisibleFromClient) {
86                     r.activity.makeVisible();
87                 }
88             }
89
90             if (!r.onlyLocalRequest) {
91                 r.nextIdle = mNewActivities;
92                 mNewActivities = r;
93                 if (localLOGV) Slog.v(
94                     TAG, "Scheduling idle handler for " + r);
95                 Looper.myQueue().addIdleHandler(new Idler());
96             }
97             r.onlyLocalRequest = false;
98
99             // Tell the activity manager we have resumed.
100             if (reallyResume) {
101                 try {
102                     ActivityManagerNative.getDefault().activityResumed(token);
103                 } catch (RemoteException ex) {
104                 }
105             }
106
107         } else {
108             // If an exception was thrown when trying to resume, then
109             // just end this activity.
110             try {
111                 ActivityManagerNative.getDefault()
112                     .finishActivity(token, Activity.RESULT_CANCELED, null);
113             } catch (RemoteException ex) {
114             }
115         }
116     }
第31行(ActivityThread->handleResumeActivity)r.window == null表示Activity还没有和Window关联起来, 因此会进入32-47行(ActivityThread->handleResumeActivity)的代码.
    第32行(ActivityThread->handleResumeActivity)会将r.window赋值成r.activity.getWindow(), 也就是Activity组件的Window.
    第33行(ActivityThread->handleResumeActivity)会将r.window.getDecorView(), 也就是DecorView取出来. 如果当前的DecorView还没有创建, 就会创建一个DecorView对象, 关于PhoneWindow的getDecorView函数的详细分析可以参考page9文档.
第35行(ActivityThread->handleResumeActivity)调用Activity的getWindowManager函数来得到WindowManager, 其实得到的是一个WindowManagerImpl对象.
第37行(ActivityThread->handleResumeActivity)将Activity的mDecor设置成r.window.getDecorView()
    第41行(ActivityThread->handleResumeActivity)将Activity的mWindowAdded设置为true,表示Activity已经有Window了.
    第42行(ActivityThread->handleResumeActivity)会调用WindowManagerImpl的addView函数, 关于addView函数的详细分析可以参考page2文件.
page2
WindowManagerImpl的addView函数的定义如下:
public void addView(View view, ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
mGlobal的类型为WindowManagerGlobal, WindowManagerGlobal的addView函数的定义如下:
1     public void addView(View view, ViewGroup.LayoutParams params,
2             Display display, Window parentWindow) {
3         if (view == null) {
4             throw new IllegalArgumentException("view must not be null");
5         }
6         if (display == null) {
7             throw new IllegalArgumentException("display must not be null");
8         }
9         if (!(params instanceof WindowManager.LayoutParams)) {
10             throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
11         }
12
13         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
14         if (parentWindow != null) {
15             parentWindow.adjustLayoutParamsForSubWindow(wparams);
16         }
17
18         ViewRootImpl root;
19         View panelParentView = null;
20
21         synchronized (mLock) {
22             // Start watching for system property changes.
23             if (mSystemPropertyUpdater == null) {
24                 mSystemPropertyUpdater = new Runnable() {
25                     @Override public void run() {
26                         synchronized (mLock) {
27                             for (ViewRootImpl viewRoot : mRoots) {
28                                 viewRoot.loadSystemProperties();
29                             }
30                         }
31                     }
32                 };
33                 SystemProperties.addChangeCallback(mSystemPropertyUpdater);
34             }
35
36             int index = findViewLocked(view, false);
37             if (index >= 0) {
38                 throw new IllegalStateException("View " + view
39                         + " has already been added to the window manager.");
40             }
41
42             // If this is a panel window, then find the window it is being
43             // attached to for future reference.
44             if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
45                     wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
46                 final int count = mViews != null ? mViews.length : 0;
47                 for (int i=0; i<count; i++) {
48                     if (mRoots[i].mWindow.asBinder() == wparams.token) {
49                         panelParentView = mViews[i];
50                     }
51                 }
52             }
53
54             root = new ViewRootImpl(view.getContext(), display);
55
56             view.setLayoutParams(wparams);
57
58             if (mViews == null) {
59                 index = 1;
60                 mViews = new View[1];
61                 mRoots = new ViewRootImpl[1];
62                 mParams = new WindowManager.LayoutParams[1];
63             } else {
64                 index = mViews.length + 1;
65                 Object[] old = mViews;
66                 mViews = new View[index];
67                 System.arraycopy(old, 0, mViews, 0, index-1);
68                 old = mRoots;
69                 mRoots = new ViewRootImpl[index];
70                 System.arraycopy(old, 0, mRoots, 0, index-1);
71                 old = mParams;
72                 mParams = new WindowManager.LayoutParams[index];
73                 System.arraycopy(old, 0, mParams, 0, index-1);
74             }
75             index--;
76
77             mViews[index] = view;
78             mRoots[index] = root;
79             mParams[index] = wparams;
80         }
81
82         // do this last because it fires off messages to start doing things
83         try {
84             root.setView(view, wparams, panelParentView);
85         } catch (RuntimeException e) {
86             // BadTokenException or InvalidDisplayException, clean up.
87             synchronized (mLock) {
88                 final int index = findViewLocked(view, false);
89                 if (index >= 0) {
90                     removeViewLocked(index, true);
91                 }
92             }
93             throw e;
94         }
95     }

第3-11行(WindowManagerGlobal->addView)判断输入参数的正确性
第13-16行(WindowManagerGlobal->addView)是在parentWindow不为null的情况下, 调用parentWindow的adjustLayoutParamsForSubWindow函数来通知父窗口
    第21行(WindowManagerGlobal->addView)会在mLock上加锁, 为的是保护mViews,mRoots, mParams三个数组的访问.
    第23-34行(WindowManagerGlobal->addView)会注册一个系统属性变化的观察者
    第36行(WindowManagerGlobal->addView)会调用findViewLocked函数查找是否已经创建过ViewRoot, 关于findViewLocked函数的详细分析可以参考page3文件
    第37-40行(WindowManagerGlobal->addView)发现已经为Activity创建过ViewRoot了, 会抛出一个异常
    第44-52行(WindowManagerGlobal->addView)是在Window为panel类型的Window, 那么会将panelParentView查找出来, 那么什么是Panel类型的Window, 应该是依附于其他的Window中吧, i am not sure.
    第54行(WindowManagerGlobal->addView)行创建一个ViewRootImpl, 并赋值给临时变量root. 关于ViewRootImpl的创建过程可以参考page4文件.
    第56行(WindowManagerGlobal->addView)将
    第58-79行(WindowManagerGlobal->addView)会将View, ViewRootImpl和LayoutParams保存到mViews, mRoots和mParams数组里, 在这个过程中, 会用System.arraycopy函数来移动数组, 这不会很慢么?
    第83-94行(WindowManagerGlobal->addView)会调用ViewRootImpl的setView函数, 一旦setView函数有异常发生, 就会将该View从WindowManagerGlobal中删除掉, 关于ViewRootImpl的setView函数的详细分析可以参考page8文件.
page3
在这篇文章里, 我们分析一下WindowManagerGlobal类的findViewLocked函数的实现:
1     private int findViewLocked(View view, boolean required) {
2         if (mViews != null) {
3             final int count = mViews.length;
4             for (int i = 0; i < count; i++) {
5                 if (mViews[i] == view) {
6                     return i;
7                 }
8             }
9         }
10         if (required) {
11             throw new IllegalArgumentException("View not attached to window manager");
12         }
13         return -1;
14     }

findViewLocked函数的逻辑很简单, 就是在mViews数组里线性查找, 并返回索引号, 如果没找到则返回-1.




猜你喜欢

转载自zzu-007.iteye.com/blog/2398791