《 Android应用setContentView与LayoutInflater加载解析机制源码分析》观后感

来源:互联网 发布:淘宝内裤拍摄 原图 编辑:程序博客网 时间:2024/06/05 19:18

原文链接: Android应用setContentView与LayoutInflater加载解析机制源码分析

1.Android 的setContentView大致流程

对于setContentView这个方法,真的是可以说习以为常,但是却没有真正的理解过这个方法,今天看了这篇文章,也觉得受益匪浅。

首先说下如何将xml文件加入activity当中,首先认识一下几个重要的对象。

1.window:是一个抽象类,提供了绘制窗口的一组通用API

2.phonewindow :继承自window,内部包含一个decorview,用于加载xml视图文件

3.decorView:activity的rootView,本身继承FramLayout,其内部包含2个子view,一个stubView,用于展示actionbar,另一个是id为content的FramLayout,用于加载传递进来的xml视图文件。


如图所示(此图甚好,套下原作者的图):

简化下源码中的代码,大致流程:

1、当activity生成的时候,会初始化一个phoneWindow,继承自Window类。

2、生成phonewindow的时候会去判断是否有decorView存在,若不存在则去new一个对象,同时会去查找xml文件定义的主题,如(android:theme="@android:style/Theme.NoTitleBar")和在代码中设置的例如(requestWindowFeature(Window.FEATURE_NO_TITLE);),用于修饰decorView的窗口如何展示。

3.然后利用( decor.addView(xmlView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)))加入到decorView中。

注意点:

不要以为当decorView被填充之后,视图便被展示在activity,以上过纯属于一个添加操作。其显示操作是在ActivityThread的handleResumeActivity方法中将它激活并显示。


2.LayoutInflater加载

对于layoutInflater,最常见的莫过于在适配器和自定义view中为了加载xml视图文件的时候出现。

常见方法:

 public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {        return inflate(resource, root, root != null);    }
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {}

其实第一中方法,在内部还是经过处理后调用了第二个方法,第一个只是加了一层封装而已。

参数解读:第一个参数是xml视图资源id;第二个参数是第一个resource生成view的父view;第三个参数是是否将resource视图加入到root中,若true,返回加入resource视图的root,若false,返回root。

inflate(xmlId, null); 只创resource建的View,然后直接返回resource
inflate(xmlId, parent); 创建resource的View,然后执行root.addView(resource, params);最后返回root。
inflate(xmlId, parent, false); 创建resource的View,然后执行resource.setLayoutParams(params);然后再返回resource
inflate(xmlId, parent, true); 创建resource的View,然后执行root.addView(resource, params);最后返回root。
inflate(xmlId, null, false); 只创建resource的View,然后直接返回temp。
inflate(xmlId, null, true); 只创建resource的View,然后直接返回temp。

典型案例如适配器中加载xml文件:

public View getView(int position, View convertView, ViewGroupparent){        if (convertView ==null) {              convertView =LayoutInflater.from(mContext).inflate(R.layout.item_view, parent,false);        }       //dosomething…       return converView;   }  
此处设置root为parent,attachToRoot为false,代表listview的item将以xmlId作为itemView,不需要返回添加了resorceView的parent,这里要知道parent是listview,若item是listview那不是乱套了。

还有要注意的一点:如listview_item.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical    android:layout_width="match_parent"    android:layout_height="100dp">    <TextView        android:id="@+id/textView"        android:textSize="30sp"        android:gravity="center"        android:background="#ffcccc"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

此为adapter的一个item的xml文件,在父view中,我们设置了 android:layout_width="match_parent",android:layout_height="100dp",我们理解一下android:layout_width和android:layout_height这2个属性,其实这2个属性并非是为当下的view赋值,而是为其父view赋值,就如layout_gravity与gravity的区别,前者是相对于父view的位置状态,而后者是相对于自身的子view的位置状态。如此可想而知,我们的android:layout_width和android:layout_height这2个属性是相对于父view的一种设置。

查看源码也可以看到:

 public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) { ····    // Temp is the root view that was found in the xml    //xml文件中的root view,根据tag节点创建view对象    final View temp = createViewFromTag(root, name, attrs, false);    ViewGroup.LayoutParams params = null;    if (root != null) {        if (DEBUG) {            System.out.println("Creating params from root: " +                    root);        }        // Create layout params that match root, if supplied        //根据root生成合适的LayoutParams实例        params = root.generateLayoutParams(attrs);        if (!attachToRoot) {            // Set the layout params for temp if we are not            // attaching. (If we are, we use addView, below)            //如果attachToRoot=false就调用view的setLayoutParams方法            temp.setLayoutParams(params);        }    }    ···}
此处可以看到类中有一个temp,此参数便是listview_item,params便是listview_item的属性对象,当root不为null的时候,就生成params,并复制给temp,这样一来listview_tem就可以正常显示,当root为null的时候,就不能正常显示。

总结一波:

想要正常显示xml时,设置root不为null,对于xml不需要设定固定宽高的时候,可选择设置root为null。










阅读全文
0 0