学徒浅析Android——从setContentView()角度分析View、Window、Activity三者关系

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

参考码源:Android Oreo 8.0.0

工具:Layout Inspector

 

我们在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,弹出检索框,点击确定。

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

 

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

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

借助LayoutInspector的分析,会发现应用布局的外层有一个根视图DecorView,

(http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/policy/DectorView.java)

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下。

http://androidxref.com/8.0.0_r4/xref/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

那么PhoneWindow对象是在哪里初始化的呢,在attach()中完成了实例化操作,

ActivityThread的掌控中,初始阶段的调用顺序如下:


 

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

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

2setContentView是如何起作用的

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值