天问

  • Blog
  • 热修复与动态加载
  • python爬虫
  • 专栏
    • 热修复与动态加载
    • NDK开发
    • 设计模式与架构
    • React Native
  • 好文转载
    • 计算机技术
    • 投资理财
    • 摄影与拍照技巧
  • 投稿
  • 关于本站及隐私政策
  • Github
StevenQ
为今天工作,为明天投资,为未来孵化一些东西!
  1. 首页
  2. 计算机技术
  3. 安卓开发
  4. 正文

简单谈谈安卓中的窗口管理系统

2017年8月13日 728点热度 4人点赞 0条评论

安卓中的窗口管理系统是一个非常复杂的系统,涉及到的对象概念非常多,主要包括Activity,Window,DecorView,WindowManager,WindowManagerService等,这里不对窗口管理系统整体做分析,主要来看看Activity,Window,DecorView以及开发者在Activity中通过setContentView设置的xml文件中配置的ContentView(估且这么叫)之间的层级关系,因为这一块的内容既与开发相关又不太过于底层,但是又能帮助我们从宏观上了解安卓的窗口系统。

  1. Window是Activity的一个成员,Window本身只是一个抽象类,具体的实现是PhoneWindow
  2. DecorView是PhoneWindow的一个内部类,本质是一个FrameLayout的ViewGroup
  3. ContentView是DecorView内部的一个子View,DecorView的子View除了ContentView外还包括与具体主题相关的标题栏等子View
  4. 开发者在xml中设置的界面会被添加到ContentView中作为子View

下面通过代码的方式来论证上述结论。

首先看看Activity,在Activity中有如下的代码片段:

<code class="language-text">public class Activity extends ContextThemeWrappe{
  private Window mWindow;
  ......
}</code>

从上述代码片段可以看到每一个Activity内部都持有一个mWindow的Window对象,然后我们看看Window的部分代码片段

public abstract class Window {
   //省略若干代码
   ...
public abstract void addContentView(View view, ViewGroup.LayoutParams params);
public abstract void setContentView(View view, ViewGroup.LayoutParams params);
   ...
  //省略若干代码
}

从这里可以看到Window仅仅只是一个抽象类而已,而且Activity中一些重要的方法实质上是通过调用Window类来实现的,如setContentView等,具体的实现是PhoneWindow类,我们看下PhoneWindow部分代码片段:

public class PhoneWindow extends Window{
    // This is the top-level view of the window, containing the window decor.
    private DecorView
}

可以看到PhoneWindow内部持有一个DecorView对象,我们来看下DecorView的定义:

<code class="language-text">public class DecorView extends FrameLayout {}
</code>

从这里可以看到DecorView本质是一个FrameLayout,即DecorView是一个ViewGroup容器。注意PhoneWindow不是View,PhoneWindow中关于View的操作很多都是通过DecorView来完成添加的。到这里Activity,Window,DecorView之间的层级关系就非常清楚了,但是开发者通过setContentView在xml文件中定义的界面与Activity,Window,DecorView之间关系是怎样的呢?这个就需要我们从setContentView的源码来分析了。首先看下Activity的setContentView函数

public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

从这里可以看到Activity的setContentView最终是通过PhoneWindow来完成的,因为getWindow()返回的是一个Window对象。所以我们接下来看下PhoneWindow的setContentView函数。

public void setContentView(int layoutResID) {
    if (mContentParent == null) {
        //初始化 id 为 android.R.id.content 的根布局,将其赋值给 mContentParent
        installDecor();
    } else {
        mContentParent.removeAllViews();
    }

    //把 Activity 中指定的布局 id 最终 inflate 到 mContentParent 中
    mLayoutInflater.inflate(layoutResID, mContentParent);

    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
}

注意这里的 installDecor()函数,这个函数非常重要,该函数做了两件非常重要的事,一个是DecorView的创建,另一个就是将android.R.id.content 的布局(本质为FrameLayout)与mContentParent关联起来。关于installDecor()函数的源码分析,大家可以参考这个,写的很不错:http://blog.csdn.net/yanbober/article/details/45970721/ 。注意另外一个很重要的语句 mLayoutInflater.inflate(layoutResID, mContentParent);该语句将id为layoutResID的布局文件,即开发者在xml中配置的文件,转化为View树然后添加到mContentParent中。

到这里Activity,Window,DecorView,ContentView,xml文件之间的层级关系就非常清楚了。即Window为Activity的成员,DecorView是PhoneWindow的内部类成员,ContentView是DecorView的子View,xml文件转化的View是ContentView的子View。了解它们之间的层级关系之后要获取xml文件中的根布局就很容易了。代码如下:

ViewGroup contentView = (ViewGroup)(getWindow().getDecorView().findViewById(android.R.id.content));
View xmlView= contentView.getChildAt(0);

如果要获取根布局下的全部子View可以使用如下代码:

public List<View> getChildView(View view){
    List<View> viewsList=new ArrayList<View>();
    if(view instanceof ViewGroup){
        ViewGroup vGroups=(ViewGroup) view;
        int nCount = vGroups.getChildCount();
        for (int i = 0; i < nCount; ++i) {
            View v = vGroups.getChildAt(i);
            viewsList.add(v);
            viewsList.addAll(getChildView(v));
        }
    }
    return viewsList;
}
List<View> xmlViewAllChild=getChildView(xmlView);

 

关于安卓窗口系统的详细讲解大家可以参看以下文章:

http://blog.csdn.net/yanbober/article/details/45970721/

http://www.jianshu.com/p/851714f5e640

https://zhuanlan.zhihu.com/p/26834562

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: 安卓
最后更新:2017年8月13日

天问

追梦追自由,穷则独善其身,达则兼济天下

打赏 点赞
下一篇 >

COPYRIGHT © 2022 天问 ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang