Android视图架构详解
作者: ztelur
联系方式:segmentfault,csdn,github
转载请注明原作者、文章来源,链接,版权归原文作者所有。
最近一直在研究View
的绘制相关的机制,发现需要补充一下Android View Architecture的相关知识,所以就特地研究了一下这方面的代码,写成本篇文章
为了节约你的时间,本篇文章内容大致如下:
Activity
,DecorView
,PhoneWindow
和ViewRoot
的作用和相关关系
Android View Architecture
先来几张图,大致展现一下Android 视图架构的大概。
感谢网友提醒,泛化和实现这两种关系的箭头画反啦。以后要仔细学一遍UML了,平时经常画,如果有错误可真是闹笑话啊。
Activity和Window
总所周知,Activity并不负责视图控制,它只是控制生命周期和处理事件,真正控制视图的是Window
。一个Activity包含了一个Window,Window才是真正代表一个窗口,也就是说Activity可以没有Window,那就相当于是Service了。在ActivityThread
中也有控制Service
的相关函数或许正好印证了这一点。
Activity
和Window
的第一次邂逅是在ActivityThread
调用Activity
的attach()
函数时。
//[window]:通过PolicyManager创建window,实现callback函数,所以,当window接收到
//外界状态改变时,会调用activity的方法,
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, String referrer, IVoiceInteractor voiceInteractor) {....mWindow = PolicyManager.makeNewWindow(this);//当window接收系统发送给它的IO输入事件时,例如键盘和触摸屏事件,就可以转发给相应的ActivitymWindow.setCallback(this);.....//设置本地窗口管理器mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken, mComponent.flattenToString(),(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);.....
}
在attach()
中,新建一个Window
实例作为自己的成员变量,它的类型为PhoneWindow
,这是抽象类Window
的一个子类。然后设置mWindow
的WindowManager
。
Window,Activity和DecorView
DecorView
是FrameLayout
的子类,它可以被认为是Android视图树的根节点视图。DecorView
作为顶级View,一般情况下它内部包含一个竖直方向的LinearLayout
,在这个LinearLayout里面有上下两个部分(具体情况和Android版本及主体有关),上面的是标题栏,下面的是内容栏。在Activity中通过setContentView所设置的布局文件其实就是被加到内容栏之中的,而内容栏的id是content,在代码中可以通过ViewGroup content = (ViewGroup)findViewById(R.android.id.content)来得到content对应的layout。
Window
中有几个视图相关的比较重要的成员变量如下所示:
mDecor
:DecorView
的实例,标示Window
内部的顶级视图mContentParent
:setContetView
所设置的布局文件就加到这个视图中mContentRoot
:是DecorView
的唯一子视图,内部包含mContentParent
,标题栏和状态栏。
Activity中不仅持有一个Window
实例,还有一个类型为View
的mDecor
实例。这个实例和Window
中的mDecor
实例有什么关系呢?它又是什么时候被创建的呢?
二者其实指向同一个对象,这个对象是在Activity
调用setContentView
时创建的。我们都知道Activity
的setContentView
实际上是调用了Window
的setContentView
方法。
@Override
public void setContentView(int layoutResID) {if (mContentParent == null) { //[window]如何没有DecorView,那么就新建一个installDecor(); //[window]} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {mContentParent.removeAllViews();}....//[window]第二步,将layout添加到mContentParentmLayoutInflater.inflate(layoutResID, mContentParent);.....
}
代码很清楚的显示了布局文件的视图是添加到mContentParent
中,而且Window
通过installDecor
来新建DecorView
。
//[window]创建一个decorView
private void installDecor() {if (mDecor == null) {mDecor = generateDecor(); //直接new出一个DecorView返回....}if (mContentParent == null) {//[window] 这一步也是很重要的.mContentParent = generateLayout(mDecor); //mContentParent是setContentVIew的关键啊.....}....
}
protected ViewGroup generateLayout(DecorView decor) {// Apply data from current theme........//[window] 根据不同的style生成不同的decorview啊View in = mLayoutInflater.inflate(layoutResource, null);// 加入到deco中,所以应该是其第一个childdecor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));mContentRoot = (ViewGroup) in; //给DecorView的第一个child是mContentView// 这是获得所谓的content ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);}.....return contentParent;
}
从上述的代码中,我们可以清楚的看到mDecor
和mContentParent
和mContentRoot
的关系。
那么,Activity
中的mDecor
是何时被赋值的?我们如何确定它和Widnow
中的mDecor
指向同一个对象呢?我们可以查看ActivityThread
的handleResumeActivity
函数,它负责处理Activity
的resume
阶段。在这个函数中,Android直接将Window
中的DecorView
实例赋值给Activity
。
final Activity a = r.activity;
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;
Window,DecorView 和 ViewRoot
ViewRoot
对应ViewRootImpl
类,它是连接WindowManagerService
和DecorView
的纽带,View的三大流程(测量(measure),布局(layout),绘制(draw))均通过ViewRoot来完成。ViewRoot
并不属于View树的一份子。从源码实现上来看,它既非View的子类,也非View的父类,但是,它实现了ViewParent
接口,这让它可以作为View
的名义上的父视图。RootView
继承了Handler
类,可以接收事件并分发,Android的所有触屏事件、按键事件、界面刷新等事件都是通过ViewRoot进行分发的。ViewRoot可以被理解为“View树的管理者”——它有一个mView成员变量,它指向的对象和上文中Window
和Activity
的mDecor
指向的对象是同一个对象。
我们来先看一下ViewRoot
的创建过程。由于ViewRoot
作为WindowMangerService
和DecorView
的纽带,只有在WindowManager
将持有DecorView
的Window
添加进窗口管理器才创建。我们可以查看WindowMangerGlobal
中的addView
函数。对WindowManager
不太熟悉的同学可以参考《Window和WindowManager解析》
public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {// 创建ViewRootImpl,然后将下述对象添加到列表中....root = new ViewRootImpl(view.getContext(), display);view.setLayoutParams(wparams);mViews.add(view);mRoots.add(root);mParams.add(wparams);....try {// 添加啦!!!!!!!!这是通过ViewRootImpl的setView来完成,这个View就是DecorView实例root.setView(view, wparams, panelParentView);} catch (RuntimeException e) {....}....
}
那么,Window
是什么时候被添加到WindowManager
中的呢?我们回到ActivityThread
的handleResumeActivity
函数。我们都知道Activity的resume阶段就是要显示到屏幕上的阶段,在Activity也就是DecorView
将要显示到屏幕时,系统才会调用addView
方法。
我们在handleResumeActivity
函数中找到了下面一段代码,它调用了Activity
的makeVisible()
函数。
// ActivityThread
r.activity.makeVisible();//Activity//[windows] DecorView正式添加并显示void makeVisible() {if (!mWindowAdded) {ViewManager wm = getWindowManager();wm.addView(mDecor, getWindow().getAttributes());mWindowAdded = true;}mDecor.setVisibility(View.VISIBLE);}
我们通过源代码发现,正式在makeVisible
函数中,系统进行了Window
的添加。
引用
http://wiki.jikexueyuan.com/project/deep-android-v1/surface.html
http://blog.csdn.net/guxiao1201/article/details/41744107
http://forlan.iteye.com/blog/2269381
Android视图架构详解相关推荐
- Android 视图架构详解
转自:http://android.jobbole.com/84519/ Activity,DecorView,PhoneWindow和ViewRoot的作用和相关关系 Android View Ar ...
- Android SystemUI 架构详解
Android SystemUI 架构详解 本文描述Android系统中一个核心应用SystemUI,详细赘述SystemUI中几大模块功能的实现过程.由于作者水平有限,如发现本文中错误的地方,欢迎指 ...
- Android MediaRecorder架构详解
1. 简介 在android中录制音频有两种方式,MediaRecorder和AudioRecord.两者的区别如下: (1) MediaRecorder 简单方便,不需要理会中间录制过程,结束录制后 ...
- android vold 加密,android vold架构详解(1)
首先上一张整体的结构类图 VOLD:Volume Daemon存储守护进程,用来为响应Usb/SD卡插入,拔出等动作提供服务. 系统启动时,通过解析init.rc文件来启动各种系统服务. 包括VOLD ...
- Android开发入门一之Android应用程序架构详解
Android应用程序架构详解如下: src/ java源代码存放目录 gen/自动生成目录 gen 目录中存放所有由Android开发工具自动生成的文件.目录中最重要的就是R.java文件.这个文件 ...
- DL之DeepLabv2:DeepLab v2算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
DL之DeepLabv2:DeepLab v2算法的简介(论文介绍).架构详解.案例应用等配图集合之详细攻略 目录 DeepLab v2算法的简介(论文介绍) 0.实验结果 1.DeepLab-v2 ...
- Android LiveData组件详解以及LiveDataBus
转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/99749323 本文出自[赵彦军的博客] 一.LiveData简介 LiveDat ...
- 《Java和Android开发实战详解》——1.2节Java基础知识
本节书摘来自异步社区<Java和Android开发实战详解>一书中的第1章,第1.2节Java基础知识,作者 陈会安,更多章节内容可以访问云栖社区"异步社区"公众号查看 ...
- 《Java和Android开发实战详解》——2.2节构建Java应用程序
本节书摘来自异步社区<Java和Android开发实战详解>一书中的第2章,第2.2节构建Java应用程序,作者 陈会安,更多章节内容可以访问云栖社区"异步社区"公众号 ...
最新文章
- UIView旋转角度
- css画钟表_纯Shading Language绘制HTML5时钟
- 并发设计模式之生产者消费者设计模式
- 4款bt search
- c语言语句的机器级表示实训,深入理解计算机系统(笔记):程序的机器级表示...
- centos7的firewall-cmd怎么让指定ip能访问指定端口?
- 一文看完“阿里云自动化运维沙龙 · 上海专场”整场干货
- GIS数据下载资源大全
- php 微信H5支付
- 分享几个快乐有趣的网站
- 修改 exchange服务器地址,绑定exchange邮箱服务器地址
- 《炬丰科技-半导体工艺》ZnO多晶薄膜异质结
- go beego在apache服务器上域名配置 --小丑
- cocos creator开发攀爬类游戏
- 精读《设计模式 - Prototype 原型模式》
- 无法正常打开网页的解决方法(情况一)
- 有关/mnt/asec /mnt/secure文件夹及app2sd原理
- 爬取东方财富股票信息网
- 基于C++的K-means聚类算法实现
- web自动化测试-绕过验证码登录
热门文章
- DaVinci Resolve 12: Advanced Color Grading DaVinci Resolve 12:高级颜色分级 Lynda课程中文字幕
- matlab零极点增益模型,[求助]怎么在GUI里面实现零极点增益计算
- matlab输入指令错误怎么修改,在MATLAB中运行程序时,显示错误: 此上下文中不允许函数定义。 怎么修改?...
- stm32f103各个型号芯片之间程序移植(stm32的兼容问题)
- ai讲师人工智能讲师计算机视觉老师叶梓:计算机视觉领域的自监督学习模型——MAE-13
- QQ授权登陆并获取qq个人信息
- 有爱的CD封面--(持续搜集中)
- flex布局详解(配图-简洁易懂)
- jt808终端鉴权_JT/T 808- 2019道路运输车辆卫星定位系统终端通信协议及数据格式...
- 解决 此更新不适用于你的计算机 安装msu文件时的错误提示