【问题标题】:How to properly handle inflated views inside a RecyclerView ViewHolder?如何正确处理 RecyclerView ViewHolder 中的膨胀视图?
【发布时间】:2018-07-31 10:38:09
【问题描述】:

我有多个布局将在我的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:

在这里,我使用变量创建了视图的引用,如果视图被回收,我将检查变量是否不为空,例如 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);
    }
}

我想知道和困惑应该在我的代码中实现哪个 ViewHolder,如果 ViewHolder 被回收,是否存在可能影响的差异?感谢您的回答和建议。

【问题讨论】:

    标签: android view android-recyclerview android-viewholder


    【解决方案1】:

    ViewHolder 是专门为防止过度膨胀而设计的,在 onBind 中这样做会导致性能非常差。

    我会使用多个itemViewTypes 并相应地膨胀布局,至少有一些东西可以回收。如果这些“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;
    }
    

    然后在创建 viewholder 时检查标志(例如将 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 之间遍历。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-16
      • 2014-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多