探讨View、Window和Activity的关系

640?wx_fmt=png&wxfrom=5&wx_lazy=1


今日科技快讯


5月4日,据国外媒体报道,富士康集团计划大力发展半导体业务,最近其调整了公司架构,设立了一个“半导体子集团”,还准备进入半导体的制造环节,已经要求半导体业务集团展开有关建设两座12英寸芯片厂的可行性研究。


作者简介


周一早上好!新的一周继续努力吧!

本篇来自 冷漠的学徒 的投稿,分享了从setContentView()角度分析View、Window、Activity三者关系,一起来看看!希望大家喜欢。

冷漠的学徒 的博客地址:

https://blog.csdn.net/lz8362


前言


我们在Activity的onCreate()方法中设置setContentView(),但是一直不明白其中的原理,正好公司在开展技术交流活动,分到的课题是View、Activity、Window的关系,借这个机会梳理一番。Activity生命周期的调用时通过ActivityThread管控的,我们在设置应用页面时,都是在onCreate()中调用setContentView()加载布局,这样就产生了三个疑惑:

  1. 为什么要在onCreate()中设置。

  2. setContentView是如何起作用的。

  3. DecorView和PhoneWindow如何结合。


正文


下面将通过源码的解读来分析这三个问题。

首先介绍一下如何在AndroidStudio中查看布局结构树,在Eclipse中,提供了工具hierarchyviewer.bat(在tools文件下),AndroidStudio将这个工具合并到自身中,并命名为Layout Inspector

使用步骤如下:

  1. 连接手机,并确保可以adb shell。

  2. 开启AndroidStudio,运行一个本地应用。

  3. 在菜单栏选择Tools->Android->Layout Inspector,弹出检索框,点击确定。

便会分析当前手机页面的布局结构。效果如图所示:

640?wx_fmt=png

640?wx_fmt=png

整个分析页面分为左中右三部分,左边是视图结构树,中间是页面展示,右边是选中视图的信息展示,我们需要关注的是视图结构树,对于视图信息我们关注红圈标记的mID就行了。

为什么要在onCreate()中设置

借助LayoutInspector的分析,会发现应用布局的外层有一个根视图DecorView,DecorView本质是一个系统自定义的FrameLayout。这个DecorView是如何出现在我们的布局中的呢?先从setContentView开始溯源找起。通过溯源会发现,在Activity中调用setContentView(int layoutID)实际上执行的是 Window.setContentView(int layoutID)。代码如下:

public void setContentView(@LayoutRes int layoutResID) {  

     getWindow().setContentView(layoutResID);  

     initWindowDecorActionBar();  

 }  

Window是一个抽象类,注解中声明Window是一个管理窗口外观和属性策略的抽象类,它的实现类将会以顶层视图的形式添加到窗口管理器中。它提供了标准的UI策略。且有一个唯一的实现类:PhoneWindow。重新回到Activity源码中搜索PhoneWindow,确实找到了这个类,同时也是getWindow()的返回值类型。注解中声明PhoneView所在包为android.view,但实际上通过检索PhoneView已经被移到了android.internal.policy下。

640?wx_fmt=png

在一个Activity对象被创建的初期,会首先依靠WindowManagerGlobal和WWM建立通信关系,WindowManagerGlobal用来向WindowManagerService注册,主要是获取到 WindowManagerService 代理对象。对外提供与WindowManagerService(WWM)的底层通信。随后ActivityThread通过performLaunchActivity调用Activity生命周期,调用顺序如下:

640?wx_fmt=png

Activity.attach()是Activity实例化后最先被调用的,这就保证了Window实例化对象的可用性。而onCreate()和onStart()是初始阶段唯一可以重写的方法,其他的都是final类型,鉴于Activity本质是管理页面交互,布局加载时机越早越有益于页面的展示。所以此时不设,更待何时呢。setConteneView(int layoutID)就在onCreate()中调用了。这样第一个问题就回答完了。

setContentView是如何起作用的

Activity在attach()中实例化了PhoneWindow对象,并且进行了绑定操作,操作如下:

mWindow = new PhoneWindow(this, window);  

mWindow.setWindowControllerCallback(this);  

mWindow.setCallback(this);  

mWindow.setOnWindowDismissedCallback(this);  

setContentView(int layoutID)最终执行的是PhoneView.setContentView(int layoutID),源码如下:

@Override  
public void setContentView(int layoutResID) {  

  // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window  

   // decor, when theme attributes and the like are crystalized. Do not check the feature  

   // before this happens.  

   if (mContentParent == null) {  

       <strong>installDecor();</strong>  

   } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {  

       mContentParent.removeAllViews();  

   }  

   if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {  

       final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResI
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值