View.inflate()和LayoutInflater.inflate()的区别

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_39251617/article/details/79362314

标签:【Android】UI


一、背景

昨天在写一个关于Viewpager的Demo时,碰到了一个OOM的问题,场景是这样的:

  1. 我要用Viewpager实现画廊效果,也就是一个屏幕显示多页
  2. 我将Viewpager所在的布局都加上了 android:clipChildren=”false”属性

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:clipChildren="false"
        tools:context="com.strivestay.viewpagerdemo.FourthActivity">
    
        <include layout="@layout/layout_toolbar"/>
    
        <android.support.v4.view.ViewPager
            android:id="@+id/vp"
            android:layout_width="match_parent"
            android:layout_height="180dp"
            android:layout_marginTop="100dp"
            android:layout_marginLeft="30dp"
            android:layout_marginRight="30dp"
            android:clipChildren="false">
        </android.support.v4.view.ViewPager>
    
    </LinearLayout>
  3. 给page的布局,我直接在根布局使用Imageview,无父布局约束

    <ImageView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/iv_banner"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:background="#009999"
        android:scaleType="centerCrop"/>
  4. 我使用View.inflate()加载布局

    for (int i = 0; i < 4; i++) {
        View view =  View.inflate(this,R.layout.item_banner,null);
        ImageView iv = (ImageView) view.findViewById(R.id.iv_banner);
        int resourceId = getResources().getIdentifier("img" + (i + 1), "drawable", getPackageName());
    //            Glide.with(this).load(resourceId).into(iv);
        iv.setImageResource(resourceId);
        list.add(view);
    }

效果

思考:
之所以出现这种效果,是因为加载page布局时,没有相关父布局的LayoutParams控制它,当它加载到Viewpager中后,又因为Viewpager的android:clipChildren=”false”,所以,page的内容显示到了viewpager外

解决:
View.inflate(this,R.layout.item_banner,vp);
第三个参数设置成了vp,是希望能够约束page布局(后来想想也没用,vp已经设置了clipChildren)

结果:

java.lang.OutOfMemoryError: Failed to allocate a 33341646 byte allocation with 16777216 free bytes and 18MB until OOM

我没有百度到,为什么这样会造成OOM,希望了解的能够给我留言,谢谢!

有效的两种解决办法:
1. 给page的布局外层套一个父布局

```
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/iv_banner"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:background="#009999"
        android:scaleType="centerCrop"/>
</LinearLayout>
```

2. 对图片进行裁切处理,或直接用glide

Glide.with(this).load(resourceId).into(iv);

效果:

具体实现在另一篇文章Viewpager

二、进入正题

由于上面的问题,我想仔细了解学习下View.inflate()和LayoutInflater.inflate()的区别,学习如下:

1. LayoutInflater.inflate()

该方法适用于所有布局填充的的场景,但使用前需要先实例化LayoutInflater对象

1. 获取LayoutInflater实例

  1. getLayoutInflater();
    这个方法可以在Activity和Fragment中使用,不过在Fragment中使用时,要传入一个bundle参数

    // Activity中使用
    LayoutInflater layoutInflater = getLayoutInflater();
    // Fragment中使用
    LayoutInflater layoutInflater = getLayoutInflater(savedInstanceState);
  2. getSystemService();
    这个为Context的方法,只要有上下文就能调用

    LayoutInflater inflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    
  3. LayoutInflater.from();
    这个是LayoutInflater的静态方法,传入上下文即可

    LayoutInflater inflater = LayoutInflater.from(this);

2. LayoutInflater.inflate()的重载

常用的是下面两种:

1. inflate(int resource,ViewGroup root,boolean attachToRoot)

resource:布局资源
root:生成View对象的父控件。为null,则返回的view就是布局资源的根布局;否则,需要参照第三个参数
attachToRoot:是否将布局资源加载到root上,以root作为最终返回view的根布局。 false,root不为null,则提供root的LayoutParams约束resource生成的view;true,root不为null,以root作为最终返回view的根布局

2. inflate(int resource,ViewGroup root)

resource:布局资源
root:生成View对象的父控件。为null,则返回的view就是布局资源的根布局;否则,返回的view以传入的root为根布局

该方法,实际还是调用了上一个方法

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

2. View.inflate()

这个是View类的静态方法,可直接调用,实际上还是使用了LayoutInflater,所以,它没有直接使用LayoutInflater.inflate()强大

public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) {
    LayoutInflater factory = LayoutInflater.from(context);
    return factory.inflate(resource, root);
}

参数含义:
context:上下文
resource:布局资源
root:生成View对象的父控件。为null,则以布局资源的根布局为返回view的根布局,否则将view加载到root中,以root作为根布局返回

3. 总结

View.inflate()是封装了LayoutInflater的inflate()方法,由于是静态方法,比较简便;但LayoutInflater相当于比View多了一个三个参数的inflate()方法,功能更强大

猜你喜欢

转载自blog.csdn.net/weixin_39251617/article/details/79362314
今日推荐