Android视图架构详解

简介: 作者: ztelur联系方式:segmentfault,csdn,github本文仅供个人学习,不用于任何形式商业目的,转载请注明原作者、文章来源,链接,版权归原文作者所有。

作者: ztelur
联系方式:segmentfaultcsdngithub

本文仅供个人学习,不用于任何形式商业目的,转载请注明原作者、文章来源,链接,版权归原文作者所有。

 最近一直在研究View的绘制相关的机制,发现需要补充一下Android View Architecture的相关知识,所以就特地研究了一下这方面的代码,写成本篇文章
 为了节约你的时间,本篇文章内容大致如下:

  • ActivityDecorViewPhoneWindowViewRoot的作用和相关关系

Android View Architecture

 先来几张图,大致展现一下Android 视图架构的大概。

View Architecutre类图
视图关系图.png
View树状结构图.png

Activity和Window

 总所周知,Activity并不负责视图控制,它只是控制生命周期和处理事件,真正控制视图的是Window。一个Activity包含了一个Window,Window才是真正代表一个窗口,也就是说Activity可以没有Window,那就相当于是Service了。在ActivityThread中也有控制Service的相关函数或许正好印证了这一点。
ActivityWindow的第一次邂逅是在ActivityThread调用Activityattach()函数时。

//[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输入事件时,例如键盘和触摸屏事件,就可以转发给相应的Activity
    mWindow.setCallback(this);
    .....
    //设置本地窗口管理器
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    .....
}

 在attach()中,新建一个Window实例作为自己的成员变量,它的类型为PhoneWindow,这是抽象类Window的一个子类。然后设置mWindowWindowManager

Window,Activity和DecorView

DecorViewFrameLayout的子类,它可以被认为是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实例,还有一个类型为ViewmDecor实例。这个实例和Window中的mDecor实例有什么关系呢?它又是什么时候被创建的呢?
 二者其实指向同一个对象,这个对象是在Activity调用setContentView时创建的。我们都知道ActivitysetContentView实际上是调用了WindowsetContentView方法。

@Override
public void setContentView(int layoutResID) {
    if (mContentParent == null) { //[window]如何没有DecorView,那么就新建一个
        installDecor(); //[window]
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }
    ....
    //[window]第二步,将layout添加到mContentParent
    mLayoutInflater.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中,所以应该是其第一个child
    decor.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;
}

 从上述的代码中,我们可以清楚的看到mDecormContentParentmContentRoot的关系。
 那么,Activity中的mDecor是何时被赋值的?我们如何确定它和Widnow中的mDecor指向同一个对象呢?我们可以查看ActivityThreadhandleResumeActivity函数,它负责处理Activityresume阶段。在这个函数中,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类,它是连接WindowManagerServiceDecorView的纽带,View的三大流程(测量(measure),布局(layout),绘制(draw))均通过ViewRoot来完成。ViewRoot并不属于View树的一份子。从源码实现上来看,它既非View的子类,也非View的父类,但是,它实现了ViewParent接口,这让它可以作为View的名义上的父视图。RootView继承了Handler类,可以接收事件并分发,Android的所有触屏事件、按键事件、界面刷新等事件都是通过ViewRoot进行分发的。ViewRoot可以被理解为“View树的管理者”——它有一个mView成员变量,它指向的对象和上文中WindowActivitymDecor指向的对象是同一个对象

 我们来先看一下ViewRoot的创建过程。由于ViewRoot作为WindowMangerServiceDecorView的纽带,只有在WindowManager将持有DecorViewWindow添加进窗口管理器才创建。我们可以查看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中的呢?我们回到ActivityThreadhandleResumeActivity函数。我们都知道Activity的resume阶段就是要显示到屏幕上的阶段,在Activity也就是DecorView将要显示到屏幕时,系统才会调用addView方法。
 我们在handleResumeActivity函数中找到了下面一段代码,它调用了ActivitymakeVisible()函数。

// 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

相关文章
|
2月前
|
安全 Android开发 iOS开发
深入探索Android与iOS的差异:从系统架构到用户体验
在当今的智能手机市场中,Android和iOS无疑是最受欢迎的两大操作系统。本文旨在探讨这两个平台之间的主要差异,包括它们的系统架构、开发环境、安全性、以及用户体验等方面。通过对比分析,我们可以更好地理解为何不同的用户群体可能会偏好其中一个平台,以及这些偏好背后的技术原因。
|
2月前
|
缓存 前端开发 Android开发
安卓开发中的自定义视图:从零到英雄
【10月更文挑战第42天】 在安卓的世界里,自定义视图是一块画布,让开发者能够绘制出独一无二的界面体验。本文将带你走进自定义视图的大门,通过深入浅出的方式,让你从零基础到能够独立设计并实现复杂的自定义组件。我们将探索自定义视图的核心概念、实现步骤,以及如何优化你的视图以提高性能和兼容性。准备好了吗?让我们开始这段创造性的旅程吧!
30 1
|
2月前
|
Android开发 Swift iOS开发
深入探索iOS与Android操作系统的架构差异及其对应用开发的影响
在当今数字化时代,移动设备已经成为我们日常生活和工作不可或缺的一部分。其中,iOS和Android作为全球最流行的两大移动操作系统,各自拥有独特的系统架构和设计理念。本文将深入探讨iOS与Android的系统架构差异,并分析这些差异如何影响应用开发者的开发策略和用户体验设计。通过对两者的比较,我们可以更好地理解它们各自的优势和局限性,从而为开发者提供有价值的见解,帮助他们在这两个平台上开发出更高效、更符合用户需求的应用。
|
3月前
|
前端开发 JavaScript 测试技术
android做中大型项目完美的架构模式是什么?是MVVM吗?如果不是,是什么?
android做中大型项目完美的架构模式是什么?是MVVM吗?如果不是,是什么?
139 2
|
3月前
|
存储 前端开发 Java
Android MVVM架构模式下如何避免内存泄漏
Android采用MVVM架构开发项目,如何避免内存泄漏风险?怎样避免内存泄漏?
120 1
|
1月前
|
存储 Linux API
深入探索Android系统架构:从内核到应用层的全面解析
本文旨在为读者提供一份详尽的Android系统架构分析,从底层的Linux内核到顶层的应用程序框架。我们将探讨Android系统的模块化设计、各层之间的交互机制以及它们如何共同协作以支持丰富多样的应用生态。通过本篇文章,开发者和爱好者可以更深入理解Android平台的工作原理,从而优化开发流程和提升应用性能。
|
1月前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统架构差异及其对开发者的影响
本文旨在通过对比分析iOS和Android两大移动操作系统的系统架构,探讨它们在设计理念、技术实现及开发者生态方面的差异。不同于常规摘要仅概述内容要点,本摘要将简要触及核心议题,为读者提供对两大平台架构特点的宏观理解,铺垫
|
1月前
|
网络协议 Linux Android开发
深入探索Android系统架构与性能优化
本文旨在为读者提供一个全面的视角,以理解Android系统的架构及其关键组件。我们将探讨Android的发展历程、核心特性以及如何通过有效的策略来提升应用的性能和用户体验。本文不包含常规的技术细节,而是聚焦于系统架构层面的深入分析,以及针对开发者的实际优化建议。
55 1
|
2月前
|
IDE 安全 Android开发
深入探索Android与iOS操作系统的架构差异
本文旨在对比分析Android和iOS两大主流移动操作系统在架构设计上的根本差异。通过详细解读两者的系统架构、开发环境、以及安全性等方面,揭示它们各自的特点及优势,为开发者选择合适的平台提供参考。
|
2月前
|
Java Linux Android开发
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。