如何正确处理RecyclerView ViewHolder中的膨胀视图?

时间:2018-07-31 10:38:10

标签: android view android-recyclerview android-viewholder

我有多个布局会在我的RecyclerView ViewHolder中膨胀,视图是否膨胀取决于传递给ViewHolder的数据集,我知道如何使用getItemViewType(),但就我而言它不适用,例如,数据集包含1,2,3,它将所有视图充气到ViewHolder容器(LinearLayout)。

带有LinearLayout容器的我的ViewHolder:

    <android.support.v7.widget.CardView 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        card_view:cardBackgroundColor="@android:color/white"
        card_view:cardCornerRadius="2dp"
        card_view:cardElevation="2dp">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">
                <include layout="@layout/layout_header" />
                    <LinearLayout
                        android:id="@+id/lnr_container"     
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical">
                    </LinearLayout>
                <include layout="@layout/layout_footer" />
            </LinearLayout>
</android.support.v7.widget.CardView>

ViewHolder1:

在这里,我使用变量创建了视图的引用,如果视图被回收,我将仅检查变量是否不为null,例如,recyclerView我将仅重置数据。

    private class ViewHolder1 extends RecyclerView.ViewHolder{
    @BindView(R.id.lnr_container)
    LinearLayout mLnrContainer;

    private RecyclerView mRecyclerView;
    private ImageView mImageView;
    private LinearLayout mLayout;

    public ViewHolder1(View itemView) {
        super(itemView);
        ButterKnife.bind(this,itemView);
    }

    public void setData(JSONObject data){
        mLnrContainer.removeAllViews();

        if (data.has("1")){
            if (mRecyclerView == null){
                mRecyclerView  = new RecyclerView(itemView.getContext());
                // other implementation
                mRecyclerView.setAdapter(new SomeAdapter(itemView.getContext(),data));
            }else {
                mRecyclerView.getAdapter().setData(data);
            }

            addView(mRecyclerView);
        }
        if (data.has("2")){
            mImageView  = new ImageView(itemView.getContext());
            addView(mImageView);
        }
        if (data.has("3")){
            mLayout = LayoutInflater.from(itemView.getContext()).inflate(R.layout.custom_layout,mLnrContainer,false);
            addView(mLayout);
        }
    }

    private void addView(View view){
        mLnrContainer.addView(view);
    }
}

ViewHolder2:

private class ViewHolder2 extends RecyclerView.ViewHolder{
    @BindView(R.id.lnr_container)
    LinearLayout mLnrContainer;

    public ViewHolder2(View itemView) {
        super(itemView);
        ButterKnife.bind(this,itemView);
    }

    public void setData(JSONObject data){
        mLnrContainer.removeAllViews();

        if (data.has("1")){
            RecyclerView mRecyclerView  = new RecyclerView(itemView.getContext(),data);
            addView(mRecyclerView);
        }
        if (data.has("2")){
            ImageView mImageView  = new ImageView(itemView.getContext());
            addView(mImageView);
        }
        if (data.has("3")){
            LinearLayout  mLayout = LayoutInflater.from(itemView.getContext()).inflate(R.layout.custom_layout,mLnrContainer,false);
            addView(mLayout);
        }
    }

    private void addView(View view){
        mLnrContainer.addView(view);
    }
}

我想知道和混淆哪个ViewHolders应该在我的代码中实现,如果ViewHolder被回收,是否有可能影响到其他差异?谢谢您的回答和建议。

1 个答案:

答案 0 :(得分:1)

ViewHolder专门用于防止过度膨胀,在onBind中这样做会导致性能很差。

我将使用多个itemViewType并相应地对布局进行充气,只是至少要回收一些东西。如果这些“ 1、2、3”不是互斥的,则会给出8种不同的布局组合。

修改您的RecyclerView.Adapter以反映可能的组合:

private static final int VIEWTYPE_FLAG_HAS_RECYCLER = 1;
private static final int VIEWTYPE_FLAG_HAS_IMAGEVIEW = 1 << 1;
private static final int VIEWTYPE_FLAG_HAS_LINEAR = 1 << 2;
// shared view pool
private final RecyclerView.RecycledViewPool adapterSharedRecycledViewPool = new RecyclerView.RecycledViewPool();

@Override
public int getItemViewType(int position) {
    JSONObject data = dataList.get(position);
    int viewType = 0;
    // each type is a flag in viewType int, this returns values from 0 to 7
    if(data.has("1"))
        viewType = VIEWTYPE_FLAG_HAS_RECYCLER;
    if(data.has("2"))
        viewType |= VIEWTYPE_FLAG_HAS_IMAGEVIEW;
    if(data.has("3"))
        viewType |= VIEWTYPE_FLAG_HAS_LINEAR;
    return viewType;
}

然后在创建视图持有者时检查标志(例如,将viewType作为构造函数参数传递):

private class ViewHolder3 extends RecyclerView.ViewHolder{
    @BindView(R.id.lnr_container)
    LinearLayout mLnrContainer;

    private RecyclerView mRecyclerView;
    private ImageView mImageView;
    private LinearLayout mLayout;

    public ViewHolder3(View itemView, int viewType) {
        super(itemView);
        ButterKnife.bind(this,itemView);

        // only need to inflate extra views once
        if((viewType & VIEWTYPE_FLAG_HAS_RECYCLER) > 0){
            mRecyclerView  = new RecyclerView(itemView.getContext());
            // adapter must handle empty dataset
            mRecyclerView.setAdapter(new SomeAdapter(itemView.getContext(), null));
            // optimization to share views between other items
            mRecyclerView.setRecycledViewPool(adapterSharedRecycledViewPool);
            addView(mRecyclerView);
        }
        if((viewType & VIEWTYPE_FLAG_HAS_IMAGEVIEW) > 0){
            mImageView  = new ImageView(itemView.getContext());
            addView(mImageView);
        }
        if((viewType & VIEWTYPE_FLAG_HAS_LINEAR) > 0){
            mLayout = LayoutInflater.from(itemView.getContext()).inflate(R.layout.custom_layout,mLnrContainer,false);
            addView(mLayout);
        }
    }

    public void setData(JSONObject data){
        // views must be ready now
        if (data.has("1")){
            mRecyclerView.getAdapter().setData(data);
        }
        if (data.has("2")){
            // bind image view if needed
        }
        if (data.has("3")){
            // bind data to linear layout as needed
        }
    }

    private void addView(View view){
        mLnrContainer.addView(view);
    }
}

注意setRecycledViewPool:这允许嵌套的recyclerViews共享其他嵌套的recyclerViews创建的视图。这样可以提高性能,但是someAdapter创建的ViewHolders必须是静态类(而不是适配器的内部类),因为这允许ViewHolders在不同的RecyclerViews / Adapters之间遍历。