面试准备之Activity、window、View之间的关系

来源:互联网 发布:安捷伦数据采集仪软件 编辑:程序博客网 时间:2024/06/05 15:42

Activity对老司机来说再熟悉不过了,Activity就像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图),而更简单的理解就是
Activity——一张白纸
view —–可以是字,也可以是图像;
window——类似碳素笔画笔,将字或者画写在纸上
下面分别讲述一下window,Activity,View,将其剖析;

一、window
window是一个比较抽象的概念,他只能通过WindowManager获取到;windowManager的里面的三个方法是addView(),updateViewLyoutView(),removeView(),
window是一个抽象的概念,每一个window都对应这一个view和ViewRootImpl,window通过ViewRootImpl和View建立联系,因此window并不是实际存在,是以View形式存在的,这点从WIndowmanager可以看出他上面他提供的三个方法都是对View进行操作的,说明view才是window的实体,通过windowmanager添加window涉及到两个layoutparams的属性flags,type
flags:控制window的显示特性,比较常用的又如下三个:

    FLAG_NOT_FOCUSABLE:        表示不需要获取焦点,也不需要各种输入事件,此标记会同时启用FLAG_NOT_TOUCH_MODAL,最终事件会直接传给下层具有焦点的window,**FLAG_NOT_TOUCH_MODAL**    在此模式下,系统会将当钱window区域以外的单击事件传递给底层的window,当前window区域的单击事件自己处理,这个标记很重要一般来说店铺需要开启此标记,否则其他window讲无法收到单击事件;FLAG_SHOW_WHEN_LOCKED开启此模式可以让window再显示锁屏界面上
    Type:表示window的类型,又三种类型,应用window,子window,系统window,        类型             解释                                                  应用window      对应Activity          子window        对应Dialog (不能单独存在,需要衣服在特定的父window中)        系统window      对应Toast和状态栏(需要声明权限才能创建);
window是分层的每个window都有对应的z-ordered,层级大的会覆盖层级小的    应用window      z-ordered(1~99)    子window        z-ordered(100~1999)    系统window      z-ordered(2000~2999)    这些值对应者WindowManger,layoutparmars的type参数,如果想要window位于所有window最顶层,那么采用较大的层级即可,如果想要系统层位于顶层还需要声明权限    <user-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>因为创建系统window是需要使用权限的,如果不申请会报         android.view.WindowManager$BadTokenException异常

上面介绍了window的概念及其分类,
下面看下如何获取到window的,

而这三个方法并不是本身构造的而是因为windowManager继承自ViewManager,而windowManager虽然继承自ViewManager,但是它是一个接口,真正的实现类是WindowManagerImpl{实现类},而在windowManager内部又通过windowManagerGlobal来进行操作,windowManagerGlobal是以工厂模式提供自己的实例(windowManagerGlobal.getInstance()),然后通过mGlobal来进行管理的addview、updateViewLyout()、removeView();在此我们一起分析mGlobal.addview(),过程
1.检查参数是否合法,如果是子window(上面已说明)还需要调整一些布局参数,
2、创建ViewRootimpl并将View添加到列表中, 在windowManagerGlobal的内部有几个重要的列表比较重要

    private final ArrayList《View》 mviews=new ArrayList<View>      //存储的是window对应的view    private final Arraylist<ViewRootimpl> mroots=new ArrayList<ViewRootimpl>  //存储ViewRootimpl    private final  Arraylist<WindowManager.LayoutParmas> mparmas= new ...//布局参数    private final ArrayList《View》 mDyingViews=new ArrayList<View>    //正在删除的View对象

3、通过ViewRootImpl来更新界面完成Window的添加过程,这个过程是由ViewRootImpl的setView方法来完成的,我们知道View的绘制过程是由ViewRootImpl来完成的,在setView内部通过requestLayout来完成异步刷新请求,在其内部,scheduleTraversals实际才是view的绘制入口,接着会通过windowSession最终来完成window的添加,由源代码可知mWindowSession的类型是IWindowSession,是一个Binder对象,真正的实现类是Sesson,也说明Window的添加过程就是一次IPC调用,在Session内部会通过WindowManagerService来实现Window的添加,到此整个window就获取并添加完成了。

二、Activity的window
通过上面的分析可以看出View是androdi的视图的呈现方式,但是View不能单独存在必须依附再window这个抽象概念上,因此有视图的地方就有window,那么哪里有这些视图的,可想而知,Activity、Dialog、Toast或者PopupWindow等,每个视图都对应着一个Window,接下来分析Activity的Window的创建;
要分析Activity的Window创建就必须了解Activity的启动过程,Activity的启动过程很复杂最终会在ActivityThread中的performLaunchActivity来完成整个Activty的启动,在这个方法中会通过类加载器创建Activity的实例病调用attach方法为期运行过程中所依赖的一系列上下文环境变量,再attach中Window对象是通过PolicyManager的makeNewWindow方法实现的,再实际调用中PolicyManager真正的实现是Policy类,是由该类中的makeNewWindow方法实现的,源码如下:

public Window makeNewWindow(Context context){    return new PhoneWindow(context);}

由上代码可知,Activity创建的就是PhoneWindow,到此Activity的window已经创建完毕,接下来分析Activity怎么附属在window上的,由于Activity是由setContentView完成的,可看下setContentView的源码,如下;

public void setContentView(int layoutResID){    getWindow.setContentView(layoutResID);    ininWindowDecoreActionBar();}

由上可知Acyivity讲具体实现交给了window,而window具体实现是PhoneWindow,所以只要看PhoneWindow的setContentView方法大致步骤。
1、如果没有DecoreView,那么就创建它。

     DecorView是个FrameLayout,是Activity中的顶级View,一般来说它包含标题栏和内部栏,内容部分的id就是“content”,完整的Id是androidR.id.content,DecorView的创建过程由installDecor来完成的再通过内部的generateDecore方法直接创建DecoreView,创建完成后PhoneWindow会通过generateLayout来加载具体的布局文件到DecorView中。

2、将View添加到DecorView的mContentParent中,通过:

mLayoutInflater。inflate(layoutResID,mContentParent)

到此为止Activity的布局文件已经添加到DecorView中了,这也直接说明了setContentView的方法来历了,

3、回调Activity的onContentChanged的方法通知Activity视图已经发生改变,因为再Activity的attach方法中已经实现CallBack,直接再Callback中处理这个回调,但是到此时我们还无法看到视图或者界面,因为这个时候的DecorView还么有被WIndowManager识别,在ActivityThread的hanleResumeActivity方法中首先会调用Activity的onResume方法,接着会调用Activity的makeVisible(),再这个方法中Decore才的完成添加和显示,如下所示:

voidmakeVisible(){    if(mWindowAdded){        ViewManager VM= getWindowManager();        vm.addView(mDecor,getWindow.getAttributes());        mWindowAdded=true;    }    mDecor.setVisiblility(View.VISIBLE);}

到此Activity的视图添加完成,view也绘制完成,最终显示出来

三、总结
通过上面的分析我们可以知道三者间大致的关系了,Activity的构造会创建一个PhoneWindow,通过PhoneWindow来实现将DecoreView添加到整个父视图中,又通过ViewRootImpl的setView将view添加,所以说Activity像一张白纸,window是画笔,view是内容,通过window再中间的调节合作最终完成的显示。希望这篇文章对大家有所帮助,在此特别感谢《Android开发艺术探索》对我的帮助,感谢生活,感谢科技,感谢分享!

附图:整体过程
这里写图片描述

原创粉丝点击