`
zzu_007
  • 浏览: 23893 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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.




分享到:
评论

相关推荐

    联想 viewroot简介

    1. **启动过程**:在Activity启动的过程中,ActivityThread的handler函数会处理LAUNCH_ACTIVITY消息,此过程中会调用ViewRoot的setView()方法。 2. **绘制请求**:requestLayout()实际上向消息队列发送了一个请求GUI...

    Activity启动流程进程启动

    创建完后,Activity 需要把创建好的界面显示到屏幕上,调用的流程为:WindowManager 类 ——&gt; ViewRoot 类 ——&gt; WMS 远程接口,这样就完成一个窗口添加到屏幕上。 知识点总结 * ActivityThread 是 Android 应用...

    Android Graphics Architecture.pdf

    3. **创建Surface**: ViewRoot通过调用`WindowManagerService.addWindow()`来为新窗口创建一个Surface,并将Surface传递给Activity。 4. **绘制视图层次结构**: Activity通过`ViewRoot.setView()`方法设置其视图层次...

    android获取根View的方法

    在Kotlin中,我们可以创建一个扩展函数来简化获取根View的过程: ```kotlin fun AppCompatActivity.getRootView(): View { return findViewById(android.R.id.content) } ``` 然后在任何Activity中,只需调用`...

    android record view,无需root权限

    在这个方法里,调用`MediaProjectionManager`的`createScreenCaptureIntent()`来获取一个意图,然后启动一个Activity来显示权限请求对话框。 4. **处理用户授权**:当用户授权后,`onActivityResult()`会被调用。在...

    Android自定义组件解析[郝留有]

    Activity一旦创建,便与一个新生成的PhoneWindow关联,从而获得一个WindowManager服务实例,此实例作为ActivityView的容器存在。在Activity的创建过程中,通过setContentView()方法设置用户界面,将各种View(视图)...

    Android_Surface系统的实现

    该对象会创建一个ViewRoot实例来处理与WMS之间的交互。 - **IWindowSession 和 IWindow 接口:**这些是标准的AIDL接口,用于ViewRoot与WMS之间的通信。IWindowSession用于跨进程通信,而IWindow则被WMS用于调用View...

    Android中View绘制流程详细介绍

    接着,Activity的根View会被添加到WindowManager中,此时,`WindowManagerImpl`会创建一个`ViewRoot`来管理这个根View。 **DecorView的创建** DecorView是Window的最顶层View,它是`PhoneWindow`的内部类,继承自`...

    Android开发艺术探索.任玉刚(带详细书签).pdf

    4.1 初识ViewRoot和DecorView 174 4.2 理解MeasureSpec 177 4.2.1 MeasureSpec 177 4.2.2 MeasureSpec和LayoutParams的对应关系 178 4.3 View的工作流程 183 4.3.1 measure过程 183 4.3.2 layout过程 193 ...

    Android开发艺术探索1

    - **Window创建过程**:了解Activity、Dialog、Toast创建Window的过程。 9. **四大组件的工作过程** - **Activity和服务**:理解它们的启动、停止、绑定等生命周期过程。 - **BroadcastReceiver**:广播接收器的...

    android 7.0非root下 实现静默安装 多种方式

    可以创建一个Intent,指定ACTION_VIEW并附加一个指向APK文件的URI。然后,使用FLAG_ACTIVITY_NEW_TASK和FLAG_GRANT_READ_URI_PERMISSION标志启动这个Intent,这样在某些情况下可以触发静默安装。但是,这种方法的...

    Android开发艺术探索

     4.1 初识ViewRoot和DecorView / 174  4.2 理解MeasureSpec / 177  4.2.1 MeasureSpec / 177  4.2.2 MeasureSpec和LayoutParams的对应关系 / 178  4.3 View的工作流程 / 183  4.3.1 measure过程 / 183  4.3.2...

    Android代码实现截屏

    2. **创建Bitmap**: 创建一个与root view相同大小的`Bitmap`对象。可以使用`Bitmap.createBitmap()`方法,传入view的宽度、高度和颜色格式。 3. **准备Canvas**: 创建一个`Canvas`对象,将刚才创建的`Bitmap`作为...

    android开发艺术探索高清完整版PDF

    / 301 8.2.3 Window的更新过程 / 303 8.3 Window的创建过程 / 304 8.3.1 Activity的Window创建过程 / 304 8.3.2 Dialog的Window创建过程 / 308 8.3.3 Toast的Window创建过程 / 311 第9章 四大组件的工作过程 ...

    view面试专题.docx

    2. **View与ViewRoot的关联** - 在`handleResumeActivity`时,`Activity`的`onResume`方法被调用。 - `WindowManager`将`DecorView`设置给`ViewRootImpl`。 - 此时`DecorView`加载到了`Window`中。 3. **View的...

    Android图形处理.ppt

    ViewRoot是一个Handler,作为View与WindowManager通信的中介。动画的绘制过程涉及递归地绘制整个窗口,包括绘制背景、可能的层保存、View内容的绘制以及子View的递归绘制。 在Android中,动画主要分为两种类型:帧...

    Android例子源码免root实现截屏.zip

    在Android平台上,开发一款应用程序以实现免root截屏的功能是一项常见的需求。这个"Android例子源码免root实现截屏.zip"文件提供了一个简单的示例,教你如何在不获取设备超级用户权限(即root权限)的情况下,让应用...

    Android核心剖析之Framework概述

    ViewRoot继承自Handler,作为WmS与客户端间通信的枢纽,负责接收来自WmS的指令,执行相应的窗口操作。W类作为Binder的子类,用于实现跨进程通信,确保服务端与客户端之间的数据交换。 **5. WindowManager类** ...

Global site tag (gtag.js) - Google Analytics