Android的Activity中setContentView到底经历了什么?

前面我们分别介绍了Android中的事件分发和视图绘制的核心流程。也掺杂着setContentView介绍了下,今天我们简单扼要专门分析下,希望有个更直观、清晰的认识。(趁这几天不太忙,多多总结…)

1、LayoutInflater的inflate(params …)参数

LayoutInflater 根据注释,意思是“把一个xml文件实例化成一个View对象”。
平时经常会使用两种写法获取LayoutInflater的实例,虽说归根结底还是一种。
1、

LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

2、

LayoutInflater layoutInflater = LayoutInflater.from(context);

其实两者一样,2是1的简化版,看源码。

LayoutInflater.java

public static LayoutInflater from(Context context) {
    LayoutInflater LayoutInflater =
            (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if (LayoutInflater == null) {
        throw new AssertionError("LayoutInflater not found.");
    }
    return LayoutInflater;
}

比如,在Activity中的快速使用。

LayoutInflater.from(this).inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)。

第一个参数resource,是表示要加载的布局文件。
第二个参数root,表示加载的resource是否需要一个父布局。
第三个参数attachToRoot,表示resource是否加载在父布局中。
对于attachToRoot有几种情况

  1. root 为null时,attachToRoot将不会起作用
  2. root 不为null,attachToRoot为true时,给resource一个root父布局,并且resource中的layout_width等参数生效。
  3. root 不为null,attachToRoot为false时,root不生效,只是将resource加载成一个View,但含有layout属性,即子视图的layout属性生效。
  4. 没有attachToRoot参数时,root !=null时,attachToRoot默认为true。
public View inflate(XmlPullParser parser, @Nullable ViewGroup root) {
    return inflate(parser, root, root != null);
}

2、inflate使用

根据上面的参数分析,我们试着去用示例验证下。毕竟这样才不容易忘记,理解也更深入。
btn_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:orientation="vertical"
    android:text="button">

</Button>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.hds.viewdraw.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"/>

</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LinearLayout mainLayout = (LinearLayout) findViewById(R.id.main_layout);
        View view = LayoutInflater.from(this).inflate(R.layout.btn_layout, null);
        mainLayout.addView(view);
    }
}

1、根据上述代码的运行结果是,Button的布局并没有根据指定的200dp展示,是linearLayout的vertical的默认子布局layoutparams:width=match_parent,height=wrap_content。
1种情况
2、MainActivity改为

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LinearLayout mainLayout = (LinearLayout) findViewById(R.id.main_layout);
        View view = LayoutInflater.from(this).inflate(R.layout.btn_layout, mainLayout,false);
        mainLayout.addView(view);
    }
}

button设置的layout生效,button被linearlayout以addView的形式加载。
2种情况
3、对于2中当前的情况,有种简单写法,直接加载到root中,结果都一样。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LinearLayout mainLayout = (LinearLayout) findViewById(R.id.main_layout);
        LayoutInflater.from(this).inflate(R.layout.btn_layout, mainLayout,true);
    }
}

3、setContentView

下面是针对目前内容的简化代码(真正伪代码,真实可不是这样子的啊),着重过程、理解关系。

public class Activity extends XXX,Window.Callback,XXX {   
    private Window mWindow;

    final void attach(Context context, ActivityThread aThread,XXX,
            Window window) {
        mWindow = new PhoneWindow(this, window);
        mWindow.setCallback(this);

    }
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
    public Window getWindow() {
        return mWindow;
    }
}
public class PhoneWindow extends Window XXX{
    private LayoutInflater mLayoutInflater;
    // This is the top-level view of the window, containing the window decor.
    private DecorView mDecor;

    public PhoneWindow(Context context) {
        super(context);
        mLayoutInflater = LayoutInflater.from(context);
    }

    @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();
        }
        mLayoutInflater.inflate(layoutResID, mContentParent);

    }
    private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            mDecor = generateDecor(-1);
        } else {
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            mContentParent = generateLayout(mDecor);
        }           
    }
    protected DecorView generateDecor(int featureId) {
        return new DecorView(context, featureId, this, getAttributes());
    }   
    protected ViewGroup generateLayout(DecorView decor) {
        return (ViewGroup)findViewById(ID_ANDROID_CONTENT);
    }

}

DecorView extends FrameLayout,所以是一个ViewGroup,且里面嵌套有个id为content的FrameLayout布局。

由上,setContentView(layoutResID)就是在contentView的基础上,使用mLayoutInflater.inflate(layoutResID, mContentParent)把layoutResID加载成一个View,直接添加到mContentParent中了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值