笔沫

有梦为马,随处可栖

  • 主页
  • 技术
  • 随想
  • 音乐
所有文章 其他

笔沫

有梦为马,随处可栖

  • 主页
  • 技术
  • 随想
  • 音乐

Activity布局加载流程源码分析(II)

2018-01-03

在Activity布局加载流程源码分析(I)文章中,已经详细分析了setContentView()加载流程,但对于装饰器DecorView怎么被加载到Window上的,上篇博文没有说到,所以本篇博文将会接着上篇博文,继续分析Activity布局的加载流程。

在开始分析之前,我们需要了解一些概念,如:

  • Window: 是一个抽象类,表示是一个窗口。Android系统中的界面,也都是以窗口的形式存在的。
  • PhoneWindow: 是Window类具体实现类,Activity中布局加载逻辑主要就是在此类中完成的。
  • DecorView:是PhoneWindow中的一个内部类,也是Window的顶级View,主要负责装载各种View。
  • WindowManager: 是Window的管理类,管理着Window的添加、更新和删除。
  • WindowManagerService(AMS):是系统窗口管理服务类,具体管理着系统各种各样的Window。
  • ViewRootImpl:是View的绘制的辅助类,所有View的绘制都离不开ViewRootImpl。

一、Activity布局及DecorView加载分析

这里,我们接着Activity布局加载流程继续分析。在布局加载流程最后,主要是通过WindowManager添加装饰器DecorView到Window中,从而实现Activity布局的加载,这里继续来看那部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
ActivityClientRecord r = performResumeActivity(token, clearHide);
.......
if (r != null) {
final Activity a = r.activity;
......
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
......
}
}

这里,简单解释一下参数。其中r.window为PhoneWindow,decor就是装饰器DecorView,wm就是WindowManager。最后通过wm.addView(decor, l)方法,实现Activity布局的加载。这里还注意到WindowManager.LayoutParams的type参数为WindowManager.LayoutParams.TYPE_BASE_APPLICATION,也即是应用窗口类型(所有程序窗口的base窗口,其他应用程序窗口都显示在它上面),具体有关Window的窗口属性,可以参考博文Android悬浮窗原理解析(Window),想了解的同学,可以点击看看,这里有比较全的Window属性解释。

我们再来看一下wm,这里定义的类型是接口ViewManager,其实它就是WindowManager,这里主要是使用设计模式的里氏替换原则(源码中很多地方都用这原则)。wm主要是通过a.getWindowManager()赋值的,所以我们主要来看看Activity中的getWindowManager()方法

1
2
3
public WindowManager getWindowManager() {
return mWindowManager;
}

mWindowMananger是Activity的一个属性变量,通过Activity的启动加载流程,Activity初始化过程中就会对mWindowManager进行赋值,而Activity初始化主要通过attach方法完成,所以我们继续来看Activity的attach方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
.......
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
......
mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}

这里是通过mWindow.getWindowManager()来赋值mWindowManager,而mWindow即PhoneWindow,这点在Activity布局加载流程中,已分析过。由于PhoneWindow是继承至Window,通过阅读源码分析知道,getWindowManager()方法,主要是window中完成实现的,所以我们具体来看看Window中的getWindowManager()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();//1.核心代码
}
mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);//2.核心代码
}
public WindowManager getWindowManager() {
return mWindowManager;
}

这里,我们先来看一下注释1,WindowManagerImpl.getDefault(),这很明显是单例模式。我们继续来看看源码

1
2
3
4
5
6
private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();
public static WindowManagerImpl getDefault() {
return sWindowManager;
}

这里wm就是WindowManagerImpl。我们来看看WindowManagerImpl类

1
2
3
public class WindowManagerImpl implements WindowManager {
......省略细节
}

我们再来看看注释2,也即LocalWindowManager类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper {
private static final String PROPERTY_HARDWARE_UI = "persist.sys.ui.hw";
private final boolean mHardwareAccelerated;
LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) {
super(wm, getCompatInfo(mContext));
mHardwareAccelerated = hardwareAccelerated ||
SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
}
public boolean isHardwareAccelerated() {
return mHardwareAccelerated;
}
public final void addView(View view, ViewGroup.LayoutParams params) {
........
super.addView(view, params);
}
}

我们继续来看看LocalWindowManager类继承的WindowManagerImpl的内部类CompatModeWrapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
static class CompatModeWrapper implements WindowManager {
private final WindowManagerImpl mWindowManager;
private final Display mDefaultDisplay;
private final CompatibilityInfoHolder mCompatibilityInfo;
CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) {
mWindowManager = wm instanceof CompatModeWrapper
? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm;
if (ci == null) {
mDefaultDisplay = mWindowManager.getDefaultDisplay();
} else {
mDefaultDisplay = Display.createCompatibleDisplay(
mWindowManager.getDefaultDisplay().getDisplayId(), ci);
}
mCompatibilityInfo = ci;
}
@Override
public void addView(View view, android.view.ViewGroup.LayoutParams params) {
mWindowManager.addView(view, params, mCompatibilityInfo);
}
@Override
public void updateViewLayout(View view, android.view.ViewGroup.LayoutParams params) {
mWindowManager.updateViewLayout(view, params);
}
@Override
public void removeView(View view) {
mWindowManager.removeView(view);
}
@Override
public Display getDefaultDisplay() {
return mDefaultDisplay;
}
@Override
public void removeViewImmediate(View view) {
mWindowManager.removeViewImmediate(view);
}
@Override
public boolean isHardwareAccelerated() {
return mWindowManager.isHardwareAccelerated();
}
}

WindowManagerImpl的内部类CompatModeWrapper实现了WindowManager接口,而WindowManager又实现了ViewManager接口

1
2
3
public interface WindowManager extends ViewManager {
......
}

我们来看看ViewManager接口

1
2
3
4
5
6
public interface ViewManager
{
public void addView(View view, ViewGroup.LayoutParams params);
public void updateViewLayout(View view, ViewGroup.LayoutParams params);
public void removeView(View view);
}

这里实现ViewManager接口的有WindowManager,而WindowManagerImpl和CompatModeWrapper也都实现WindowManager接口,从而间接实现了ViewManager接口,也都实现的添加,更新和删除View的方法。

所以,在最开始处,以ViewManager定义的wm其实也就是LocalWindowManager,通过相互继承调用,其实最后调用的是WindowManagerImpl中的addView()方法,我们继续来看看此方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
public void addView(View view) {
addView(view, new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE));
}
public void addView(View view, ViewGroup.LayoutParams params) {
addView(view, params, null, false);
}
public void addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) {
addView(view, params, cih, false);
}
private void addView(View view, ViewGroup.LayoutParams params,
CompatibilityInfoHolder cih, boolean nest) {
if (false) Log.v("WindowManager", "addView view=" + view);
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException(
"Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
ViewRootImpl root;
View panelParentView = null;
.......
root = new ViewRootImpl(view.getContext());
root.mAddNesting = 1;
if (cih == null) {
root.mCompatibilityInfo = new CompatibilityInfoHolder();
} else {
root.mCompatibilityInfo = cih;
}
view.setLayoutParams(wparams);
if (mViews == null) {
index = 1;
mViews = new View[1];
mRoots = new ViewRootImpl[1];
mParams = new WindowManager.LayoutParams[1];
} else {
index = mViews.length + 1;
Object[] old = mViews;
mViews = new View[index];
System.arraycopy(old, 0, mViews, 0, index-1);
old = mRoots;
mRoots = new ViewRootImpl[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
old = mParams;
mParams = new WindowManager.LayoutParams[index];
System.arraycopy(old, 0, mParams, 0, index-1);
}
index--;
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
}
// do this last because it fires off messages to start doing things
root.setView(view, wparams, panelParentView);
}

这里有三个数组mViews,mRoots,mParams变量,mViews主要保存向Window中添加的View,mRoots主要保存实现绘制View的ViewRootImpl,mParams主要保存添加的Window参数,最后每一个添加的View都会调用root.setView(view, wparams, panelParentView)方法,实现View的绘制。关于这三个参数的作用,是因为WindowManager中可能添加多个Window,多个View,所以需要保存起来,方便删除和更新。

关于WindowManagerImpl的源码,这里需要注意一下,由于我用的版本是Andorid4.1.1_r1,源码如上,而在大于Andorid4.1.1_r11的版本,如Android5.1.1中的WindowManagerImpl源码的addView方法,主要是通过WindowManagerGlobal来实现的,逻辑也都和Andorid4.1.1_r1一样,只是把部分逻辑封装成WindowManagerGlobal,这里我就不多说,想了解的同学,可以自行查看。

到这里,DecorView添加入Window的流程就分析完了。接下来主要就是DecorView的绘制流程,也即View的绘制流程。

注:源码采用android-4.1.1_r1版本,建议下载源码然后自己走一遍流程,这样更能加深理解。

二、参考文档

Activity布局加载流程源码分析

Activity启动流程源码分析(应用中)

Android悬浮窗原理解析(Window)

赏

感谢认可,么么哒

支付宝
微信
  • 技术
  • Android
  • Android框架源码解析

扫一扫,分享到微信

微信分享二维码
DecorView绘制流程源码分析
Activity布局加载流程源码分析(I)
© 2019 笔沫
Hexo Theme Yilia by Litten
  • 所有文章
  • 其他

tag:

  • 技术
  • Android
  • Activity的启动模式
  • Android注解
  • Java反射机制
  • Java动态代理
  • Android基础
  • MVP
  • NDK
  • JNI C/C++
  • 开源框架
  • AS Gradle优化
  • 博客搭建
  • 设计模式
  • Fragment
  • Rxjava
  • Rxandroid
  • 响应式编程
  • 随想
  • 你本是一个肉体,是什么驱使你前行
  • 原创
  • 笔沫拾光
  • Java
  • Java基础
  • 王阳明心学
  • 中国历史
  • 人生的意义
  • 演讲
  • 执着的人是幸福的
  • 郭川
  • Android框架源码解析
  • 加解密算法
  • Binder通信机制
  • 开源框架源码解析
  • LeakCanary框架源码分析
  • Java集合类
  • 转载
  • Http文件断点续传
  • Logger框架源码解析
  • Android应用程序入口源码解析
  • DecorView绘制流程
  • Android消息机制源码解析
  • Activity启动流程
  • Butterknife框架源码解析
  • 我之存在,因为有你
  • 霍华德*舒尔茨
  • Android相机
  • Camera
  • 悬浮窗
  • WindowManager

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 风光摄影
  • 星空摄影
  • 人像摄影
  • 学习站点