具有多种视图类型的Recyclerview:内部工作原理?

时间:2017-10-27 14:33:53

标签: android android-recyclerview android-adapter

我已经能够创建一个可以托管两个不同ViewHolder的RecyclerView,具体取决于我模型中的数据。然而,我仍然对RecyclerView和相应的适配器如何使其工作感到困惑。

我的理由如下:当只使用一个viewType时,RecyclerView使用Adapters onCreateViewHolder 方法创建填充一个屏幕所需的ViewHolders。此数量可能小于所需的总行数。 创建每个ViewHolder后,它要求Adapter使用 onBindViewHolder 将模型数据绑定到ViewHolder 在滚动列表时,RecyclerView始终重用相同的ViewHolders,但使用之前的 onBindViewHolder 方法将不同的数据绑定到它们。它可以毫无问题地执行此操作,因为model和viewType之间存在1-1关系。

但是当有多个viewTypes时,我感到困惑。 在我的用例中,两种视图类型之间只有很小的差异。类型A只有两个TextView,类型B有两个textViews 一个Button。我创建了一个Abstract SimpleHolder ViewHolder类,它有两个TextView。对于类型A,除了调用超类构造函数之外,具体类不会做太多事情。对于类型B,我还扩展了该抽象超类,并为Button提供了额外的属性。

在我的列表中说出前10个项目中的5个是A类型,5个是B类型(随机放置)。 RecyclerView必须创建ViewHolders,并且看到它必须为类型A创建5个ViewHolders,为类型B创建5个。它知道在使用哪个时因为我实现了 getItemViewType 方法并使用了 onCreateViewHolder 中的viewType参数。 我猜在内部看起来像这样:

  1. ViewHolder A
  2. ViewHolder A
  3. ViewHolder B
  4. ViewHOlder A
  5. ViewHolder B
  6. ViewHolder B
  7. ViewHolder A
  8. ViewHolder B
  9. ViewHolder A
  10. ViewHolder B
  11. 这里的数字是屏幕上的位置。当用户没有滚动时,一切都很好。但是一旦他/她做了,事情就会开始发生变化。我的屏幕上的位置3可能不再存在类型B,但现在是类型A.但是位置3是"保留"对于B型! RecyclerView如何处理此问题?

    我可以想到以下选项,但我不确定。

    • RecyclerView只会抛弃旧的ViewHolder并创建一个新的类型A.这有点违背了RecyclerView的想法。
    • RecyclerView实际上并没有为其ViewHolder设置固定位置,只是一个池。使用一个ViewType时,它有一个池。使用多个时,它只需从多个池中的ViewHolder对象中获取,并可以自由重新排序。看起来更复杂,但不会不必要地丢弃ViewHolder对象。

    这是两个中的一个吗?或者是其他东西?对于文本墙感到抱歉,但我想完全解释我的推理。

    必要时编码:

    private abstract class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private TextView mTitleTextView;
        private TextView mDateTextView;
    
        private Crime mCrime;
    
        private CrimeHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
            super(inflater.inflate(viewType, parent, false));
            itemView.setOnClickListener(this);
            mTitleTextView = (TextView) itemView.findViewById(R.id.crime_title);
            mDateTextView = (TextView) itemView.findViewById(R.id.crime_date);
        }
    
        public void bind(Crime crime) {
            Log.d("CrimeHolder", "bind");
            this.mCrime = crime;
            mTitleTextView.setText(mCrime.getTitle());
            mDateTextView.setText(mCrime.getDate().toString());
        }
    
        @Override
        public void onClick(View view) {
            Toast.makeText(getActivity(), mCrime.getTitle() + " clicked", Toast.LENGTH_SHORT).show();
        }
    }
    
    private class SimpleCrimeHolder extends CrimeHolder {
    
        private SimpleCrimeHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
            super(inflater, parent, viewType);
            Log.d("SimpleCrimeHolder", "Constructor");
        }
    }
    
    private class SeriousCrimeHolder extends CrimeHolder {
        private Button mContactPoliceButton;
    
        private SeriousCrimeHolder(LayoutInflater inflater, ViewGroup parent, int viewType) {
            super(inflater, parent, viewType);
            Log.d("SeriousCrimeHolder", "Constructor");
    
            mContactPoliceButton = (Button) itemView.findViewById(R.id.contact_police_button);
            mContactPoliceButton.setOnClickListener(view ->
                    Toast.makeText(getActivity(), "Contacting Police!", Toast.LENGTH_SHORT).show());
        }
    }
    
    
    private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
        private List<Crime> mCrimes;
    
        private CrimeAdapter(List<Crime> crimes) {
            this.mCrimes = crimes;
        }
    
        @Override
        public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
            if (viewType == R.layout.list_item_crime) {
                Log.d("Adapter", "onCreateViewHolder - SimpleCrimeHolder");
                return new SimpleCrimeHolder(layoutInflater, parent, viewType);
            } else {
                Log.d("Adapter", "onCreateViewHolder - SeriousCrimeHolder");
                return new SeriousCrimeHolder(layoutInflater, parent, viewType);
            }
        }
    
        @Override
        public void onBindViewHolder(CrimeHolder holder, int position) {
            Log.d("Adapter", "onBindViewHolder - positie " + position);
    
            Crime crime = mCrimes.get(position);
            holder.bind(crime);
        }
    
        @Override
        public int getItemViewType(int position) {
            Log.d("Adapter", "getItemViewType pos " + position + " - crime is srs: " + mCrimes.get(position).requiresPolice());
            if (mCrimes.get(position).requiresPolice()) {
                return R.layout.list_item_serious_crime;
            } else {
                return R.layout.list_item_crime;
            }
        }
    
        @Override
        public int getItemCount() {
            return mCrimes.size();
        }
    }
    

    }

0 个答案:

没有答案