当前位置: 首页 > news >正文

Android 从SetContentView()谈起

当我们新建一个工程的时候,选择生成一个Activity,AS会自动给我们生成一个界面,那么这个界面是怎么生成的呢,下面我们就来分析一下:

Activity中的代码:

@Overrideprotected
 void onCreate(Bundle savedInstanceState) {    
          super.onCreate(savedInstanceState);    
          setContentView(R.layout.activity_main);}
复制代码

XML中的代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"   
 android:layout_width="match_parent"    
 android:layout_height="match_parent">  
  <EditText     
     android:layout_width="match_parent"     
     android:layout_height="match_parent"   
     android:layout_margin="15dp"     
     android:gravity="top"     
     android:hint="这是一个EditTextView"       
     android:inputType="textMultiLine"  
     android:maxLines="20"     
     android:minLines="6"     
     android:textSize="30sp" />
  </RelativeLayout>
复制代码

用Hierarchy viewer工具来查看一下结构图: ![@P8]6~ZC7~MJ~LJFG(DPBWA.png](http://upload-images.jianshu.io/upload_images/587163-e85daee233003243.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

DecorView以及它的子View一目了然,先看下SetContentView()的实现:

@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) {      
   installDecor(); 
   } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {   
   mContentParent.removeAllViews();   
   }   
 if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {   
     final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,                getContext());      
     transitionTo(newScene);   
 } else {    
    mLayoutInflater.inflate(layoutResID, mContentParent);   
 }  
  mContentParent.requestApplyInsets();  
  final Callback cb = getCallback();  
  if (cb != null && !isDestroyed()) {    
    cb.onContentChanged();   
 }}
复制代码
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
//mContentParent 是放置窗体内容的容器,也就是我们 setContentView()
 //时所加入的 View 视图树
private ViewGroup mContentParent;
复制代码

DecorView是PhoneWindow的一个内部类,同时DecorView也是Activiy的顶级View,一般来说DecorView的内部包括导航栏(NavigationBar)和状态栏(StatusBar),但这个会随着主题的变化而发生改变。刚开始mContentParent的值是null,所以会走installDecor():

if (mDecor == null) {   
   mDecor = generateDecor(); 
   mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); 
   mDecor.setIsRootNamespace(true);  
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {  
      mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);    
  }}
if (mContentParent == null) { 
   mContentParent = generateLayout(mDecor);   
 // Set up decor part of UI to ignore fitsSystemWindows if appropriate.   
   mDecor.makeOptionalFitsSystemWindows();  
   final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(R.id.decor_content_parent);
复制代码
protected DecorView generateDecor() {  
  return new DecorView(getContext(), -1);
}
复制代码

在installDecor()里面通过调用generateDecor()方法来初始化DecorView,此时DecorView什么都没有,只是一个空的FrameLayout,往下走,来到generateLayout(mDecor),跳过一些主题布局设置,直接来到关键代码:

mDecor.startChanging();
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {  
  throw new RuntimeException("Window couldn't find content container view");
}
复制代码
/** * The ID that the main layout in the XML layout file should have. */
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
复制代码

DecorView通过generateLayout(mDecor)加载到具体的布局文件,具体的布局文件和系统版本以及主题有关,ID_ANDROID_CONTENT对应的即是R.id.content,也是我们通过SetContentView()中设置的布局id,走完installDecor(),我们继续看PhoneWindow中的SetContentView()方法,

if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {  
  final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,getContext());  
  transitionTo(newScene);
 } else {   
 mLayoutInflater.inflate(layoutResID, mContentParent);
 }
复制代码

接下来就简单了,mLayoutInflater.inflate(layoutResID, mContentParent),因为前面通过installDecor()创建了DecorView,因此这一步就是将Activity的布局(layoutResID)添加到mContentParent中了,到这里为止,Activity的布局文件就已经添加到DecorView里面了,继续看SetcontentView():

mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {  
  cb.onContentChanged();
}
复制代码

由于Activity实现了Window的Callback接口,

并且Activity的布局文件已经添加到DecorView里的mContentParent里了,当执行cb.onContentChanged()后,Activity就会回调onContentChanged()方法,由于Activity的onContentChanged()是个空实现,我们可以在子Activity中处理这个回调处理相应逻辑,到这里为止DecorView就已经被创建并初始化完毕。

转载于:https://juejin.im/post/5a33e7fd6fb9a0452341f3b8

相关文章:

  • 为什么volatile不能保证原子性而Atomic可以?
  • SQL优化常用方法44
  • NoSQL
  • session再次理解
  • 陈杰:无服务器架构,让云端开发更纯粹
  • Redis的发布订阅及.NET客户端实现
  • 动态载入数据的无刷新TreeView控件(8)
  • ubuntu-基本命令篇-13-用户管理
  • 四大中三家已面向客户推出机器人业务解决方案?别逗了,先用机器人自我革命吧! post by 上海嘉冰信息技术...
  • python基础实践(二)
  • [Spring Cloud Task]3 框架配置详解
  • node.js
  • 本周末预计更新博客内容
  • 微信开发https服务搭建
  • wii 入门之路--fatt
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • Apache Spark Streaming 使用实例
  • ES10 特性的完整指南
  • PHP面试之三:MySQL数据库
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 对超线程几个不同角度的解释
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 网页视频流m3u8/ts视频下载
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 以太坊客户端Geth命令参数详解
  • 译米田引理
  • 赢得Docker挑战最佳实践
  • 在Docker Swarm上部署Apache Storm:第1部分
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • AI算硅基生命吗,为什么?
  • 浅谈sql中的in与not in,exists与not exists的区别
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #AngularJS#$sce.trustAsResourceUrl
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (层次遍历)104. 二叉树的最大深度
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (三)Honghu Cloud云架构一定时调度平台
  • (转)Scala的“=”符号简介
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • .NET CLR Hosting 简介
  • .NET CORE 3.1 集成JWT鉴权和授权2
  • .net framework 4.0中如何 输出 form 的name属性。
  • .NET Framework杂记
  • .net 无限分类
  • .NET中GET与SET的用法
  • .vollhavhelp-V-XXXXXXXX勒索病毒的最新威胁:如何恢复您的数据?
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d
  • @Conditional注解详解
  • @FeignClient 调用另一个服务的test环境,实际上却调用了另一个环境testone的接口,这其中牵扯到k8s容器外容器内的问题,注册到eureka上的是容器外的旧版本...
  • @ModelAttribute注解使用
  • @SentinelResource详解
  • [ACL2022] Text Smoothing: 一种在文本分类任务上的数据增强方法
  • [C#]使用DlibDotNet人脸检测人脸68特征点识别人脸5特征点识别人脸对齐人脸比对FaceMesh