簡體   English   中英

Android RecyclerView items shuffles on scroll

[英]Android RecyclerView items shuffles on scroll

我的多視圖類型 RecyclerView 適配器的項目/單元格在滾動上隨機播放。 我通過以下所有可能的解決方案 go 但沒有一個工作。

1.

@Override
public long getItemId(int position) {
   return mDataset.get(position).hashCode();
   or
   return mDataset.get(position).getBaseFormElementId();
}

setHasStableIds(true);
  1. 增加了 RecyclerView 的緩存

如果有人有任何解決方案,請分享。

我的適配器 Class

public class FormAdapter extends RecyclerView.Adapter<BaseViewHolder>  {

private Context mContext;
private List<BaseFormElement> mDataset;


public FormAdapter(Context context) {
    mContext = context;
    mDataset = new ArrayList<>();
    setHasStableIds(true);
 }



public List<BaseFormElement> getDataset() {
    return mDataset;
}


public OnFormElementValueChangedListener getValueChangeListener() {
    return mListener;
}


@Override
public int getItemCount() {
    return mDataset.size();
}


@Override
public int getItemViewType(int position) {
    return mDataset.get(position).getType();
}

@Override
public long getItemId(int position) {
    //return super.getItemId(position);

    return mDataset.get(position).getBaseFormElementId();
}


@NonNull
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    // get layout based on header or element type
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View v;
    switch (viewType) {
        case BaseFormElement.TYPE_HEADER:
            v = inflater.inflate(R.layout.form_element_header, parent, false);
            return new FormElementHeader(v);
        case BaseFormElement.TYPE_EDIT_TEXT:
            v = inflater.inflate(R.layout.form_element, parent, false);
            return new FormElementEditTextViewHolder(v, new FormItemEditTextListener(this));
        case BaseFormElement.TYPE_PICKER_DATE:
            v = inflater.inflate(R.layout.form_element, parent, false);
            return new FormElementPickerDateViewHolder(v, mContext, this);
        case BaseFormElement.TYPE_PICKER_TIME:
            v = inflater.inflate(R.layout.form_element, parent, false);
            return new FormElementPickerTimeViewHolder(v, mContext, this);
        case BaseFormElement.TYPE_PICKER_SINGLE:
            v = inflater.inflate(R.layout.form_element, parent, false);
            return new FormElementPickerSingleViewHolder(v, mContext, this, new FormItemEditTextListener(this));
        case BaseFormElement.TYPE_PICKER_MULTI:
            v = inflater.inflate(R.layout.formelementlabel, parent, false);
            return new FormElementPickerMultiViewHolder(v, mContext, this);
        case BaseFormElement.TYPE_IMAGE_REMARKS:
            v = inflater.inflate(R.layout.formelementlabel, parent, false);
            return new FormElementImageWithRemarksViewHolder(v, mContext, this);
        case BaseFormElement.TYPE_SWITCH:
            v = inflater.inflate(R.layout.form_element_switch, parent, false);
            return new FormElementSwitchViewHolder(v, mContext, this);
        case BaseFormElement.TYPE_SEGMENT:
            v = inflater.inflate(R.layout.form_element_switch, parent, false);
            return new FormElementSwitchViewHolder(v, mContext, this);
        case BaseFormElement.TYPE_LABEL:
            v = inflater.inflate(R.layout.formelementlabel, parent, false);
            return new FormElementLabelViewHolder(v, clicklistner);
        case BaseFormElement.TYPE_IMAGE:
            v = inflater.inflate(R.layout.formelementlabel, parent, false);
            return new FromElementImageViewHolder(v, mContext, this);
        case BaseFormElement.TYPE_VIDEO:
            v = inflater.inflate(R.layout.formelementlabel, parent, false);
            return new FormElementVideoViewHolder(v, mContext, this);
        case BaseFormElement.DIALOG_LIST:
            v = inflater.inflate(R.layout.form_element_mmv, parent, false);
            return new FormElementDialogListViewHolder(v, mContext, this);
        case BaseFormElement.TYPE_SLIDER:
            v = inflater.inflate(R.layout.formelementlabel, parent, false);
            return new FormElementSliderViewHolder(v, mContext, this);
        default:
            v = inflater.inflate(R.layout.form_element, parent, false);
            return new FormElementEditTextViewHolder(v, new FormItemEditTextListener(this));
    }
}


@Override
public void onBindViewHolder(BaseViewHolder holder, final int position) {
    // gets current object
    BaseFormElement currentObject = mDataset.get(position);
    holder.bind(position, currentObject, mContext);
}

}

我研究過這種類型的RecyclerView ,這里是DynamicAdapter class 與多view-type一起使用。 我希望您對如何使用它有所了解。

    public class DynamicAdapter extends RecyclerView.Adapter <BaseViewHolder> {

  private static final String TAG = "DynamicAdapter";
  private static final int VIEW_EMPTY = 0;
  private static final int VIEW_EDIT_TEXT = 1;
  private static final int VIEW_SIGNATURE = 2;
  private static final int VIEW_UPLOAD = 3;
  private static final int VIEW_DATE_TIME = 4;
  private static final int VIEW_DATE_RANGE = 5;
  private static final int VIEW_DATE = 6;
  private static final int VIEW_DESCRIPTION = 7;
  private static final int VIEW_UNDEFINED = 8;

  ArrayList <FormData> formDataList;
  private Context context;
  private AdapterListener adapterListener;

  public DynamicAdapter(ArrayList <FormData > formDataList) {
   this.formDataList = formDataList;
  }

  public void setAdapterListener(AdapterListener adapterListener) {
   this.adapterListener = adapterListener;
  }
  @NonNull
  @Override
  public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
   this.context = parent.getContext();
   switch (viewType) {
    case VIEW_EDIT_TEXT:
     ItemDynamicFormEdittextBinding edittextBinding = ItemDynamicFormEdittextBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new EditTextViewHolder(edittextBinding);
    case VIEW_NUMBER:
     ItemDynamicFormNumberBinding numberBinding = ItemDynamicFormNumberBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new NumberViewHolder(numberBinding);
    case VIEW_EMAIL:
     ItemDynamicFormEmailBinding emailBinding = ItemDynamicFormEmailBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new EmailViewHolder(emailBinding);
    case VIEW_UPLOAD:
     ItemDynamicFormUploadBinding uploadBinding = ItemDynamicFormUploadBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new UploadViewHolder(uploadBinding);
    case VIEW_DATE_RANGE:
     ItemDynamicFormDateRangeBinding rangeBinding = ItemDynamicFormDateRangeBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new DateRangeViewHolder(rangeBinding);
    case VIEW_DATE_TIME:
     ItemDynamicFormDateTimeBinding dateTimeBinding = ItemDynamicFormDateTimeBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new DateTimeViewHolder(dateTimeBinding);
    case VIEW_DATE:
     ItemDynamicFormDateBinding dateBinding = ItemDynamicFormDateBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new DateViewHolder(dateBinding);
    case VIEW_DESCRIPTION:
     ItemDynamicFormDescriptionBinding descriptionBinding = ItemDynamicFormDescriptionBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new DescriptionViewHolder(descriptionBinding);
    case VIEW_UNDEFINED:
     ItemDynamicFormUnknownBinding unknownBinding = ItemDynamicFormUnknownBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new UnknownViewHolder(unknownBinding);
    default:
     ItemDynamicFormEmptyViewBinding emptyViewBinding = ItemDynamicFormEmptyViewBinding
      .inflate(LayoutInflater.from(parent.getContext()), parent, false);
     return new EmptyViewHolder(emptyViewBinding);
   }
  }
  @Override
  public void onBindViewHolder(@NonNull BaseViewHolder holder, final int position) {
   holder.onBind(position);
  }

  @Override
  public int getItemCount() {
   return formDataList.size();
  }

  @Override
  public int getItemViewType(int position) {
   if (formDataList != null && !formDataList.isEmpty()) {
    if (formDataList.get(position) != null &&
     formDataList.get(position).getType() != null) {
     switch (formDataList.get(position).getType()) {
      case TEXT:
       return VIEW_EDIT_TEXT;
      case CAMERA:
       return VIEW_CAMERA;
      case TOGGLE:
       return VIEW_TOGGLE;
      case NUMBER:
       return VIEW_NUMBER;
      case EMAIL:
       return VIEW_EMAIL;
      case DATE_RANGE:
       return VIEW_DATE_RANGE;
      case DATE_TIME:
       return VIEW_DATE_TIME;
      default:
       return VIEW_UNDEFINED;
     }
    } else {
     return VIEW_UNDEFINED;
    }
   } else {
    return VIEW_EMPTY;
   }
  }

  /**
   * Class used to handle all the text fields for email,text & number.
   */
  private class EditTextViewHolder extends BaseViewHolder {

   ItemDynamicFormEdittextBinding mBinding;

   EditTextViewHolder(ItemDynamicFormEdittextBinding binding) {
    super(binding.getRoot());
    Log.e(TAG, "EditTextViewHolder: ------------>>");
    this.mBinding = binding;
    mBinding.edDynamicFormText.addTextChangedListener(new TextWatcher() {
     @Override
     public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

     }

     @Override
     public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
      formDataList.get(getAdapterPosition()).setEnteredValue(charSequence.toString());
     }

     @Override
     public void afterTextChanged(Editable editable) {

     }
    });
   }

   @Override
   public void onBind(int position) {
    final FormData formData = formDataList.get(position);
    FormEdittextViewModel emptyItemViewModel = new FormEdittextViewModel(formData);
    mBinding.setViewModel(emptyItemViewModel);

    // Immediate Binding
    // When a variable or observable changes, the binding will be scheduled to change before
    // the next frame. There are times, however, when binding must be executed immediately.
    // To force execution, use the executePendingBindings() method.
    mBinding.executePendingBindings();
   }
  }

  /**
   * Class used to handle all the text fields for email, text & number.
   */
  private class NumberViewHolder extends BaseViewHolder {

   ItemDynamicFormNumberBinding mBinding;

   NumberViewHolder(ItemDynamicFormNumberBinding binding) {
    super(binding.getRoot());
    this.mBinding = binding;

    mBinding.edDynamicFormNumber.addTextChangedListener(new TextWatcher() {
     @Override
     public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

     }

     @Override
     public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
      formDataList.get(getAdapterPosition()).setEnteredValue(charSequence.toString());
     }

     @Override
     public void afterTextChanged(Editable editable) {

     }
    });
   }

   @Override
   public void onBind(int position) {
    final FormData formData = formDataList.get(position);
    mBinding.setViewModel(new FormNumberViewModel(formData));
    // Immediate Binding
    // When a variable or observable changes, the binding will be scheduled to change before
    // the next frame. There are times, however, when binding must be executed immediately.
    // To force execution, use the executePendingBindings() method.
    mBinding.executePendingBindings();
   }
  }

  /**
   * Class used to handle all the text fields for email, text & number.
   */
  private class EmailViewHolder extends BaseViewHolder {

   ItemDynamicFormEmailBinding mBinding;

   EmailViewHolder(ItemDynamicFormEmailBinding binding) {
    super(binding.getRoot());
    this.mBinding = binding;
    mBinding.edDynamicFormEmail.addTextChangedListener(new TextWatcher() {
     @Override
     public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

     }

     @Override
     public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
      formDataList.get(getAdapterPosition()).setEnteredValue(charSequence.toString());
     }

     @Override
     public void afterTextChanged(Editable editable) {

     }
    });
   }

   @Override
   public void onBind(int position) {
    final FormData formData = formDataList.get(position);

    //val radioButton = mBinding.root.findViewById(R.id.radioButtton) as RadioButton
    FormEmailViewModel emptyItemViewModel = new FormEmailViewModel(formData);
    mBinding.setViewModel(emptyItemViewModel);

    // Immediate Binding
    // When a variable or observable changes, the binding will be scheduled to change before
    // the next frame. There are times, however, when binding must be executed immediately.
    // To force execution, use the executePendingBindings() method.
    mBinding.executePendingBindings();
   }
  }

  /**
   * Class used to handle all the text fields for description only.
   */
  private class DescriptionViewHolder extends BaseViewHolder {

   ItemDynamicFormDescriptionBinding mBinding;

   DescriptionViewHolder(ItemDynamicFormDescriptionBinding binding) {
    super(binding.getRoot());
    this.mBinding = binding;
    mBinding.edDynamicFormDesc.addTextChangedListener(new TextWatcher() {
     @Override
     public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

     }

     @Override
     public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
      formDataList.get(getAdapterPosition()).setEnteredValue(charSequence.toString());
     }

     @Override
     public void afterTextChanged(Editable editable) {

     }
    });
   }

   @Override
   public void onBind(int position) {
    final FormData formData = formDataList.get(position);

    FormDescriptionViewModel emptyItemViewModel = new FormDescriptionViewModel(formData);
    mBinding.setViewModel(emptyItemViewModel);

    // Immediate Binding
    // When a variable or observable changes, the binding will be scheduled to change before
    // the next frame. There are times, however, when binding must be executed immediately.
    // To force execution, use the executePendingBindings() method.
    mBinding.executePendingBindings();
   }
  }
  /**
   * Class used to select pic form device and upload to server.
   */
  private class UploadViewHolder extends BaseViewHolder
  implements FormUploadViewModel.UploadListener {
   private ItemDynamicFormUploadBinding mBinding;

   private UploadViewHolder(ItemDynamicFormUploadBinding mBinding) {
    super(mBinding.getRoot());
    this.mBinding = mBinding;
   }

   @Override
   public void onBind(int position) {
    final FormData data = formDataList.get(position);

    FormUploadViewModel uploadViewModel = new FormUploadViewModel(data, this);
    mBinding.setViewModel(uploadViewModel);
    // Immediate Binding
    // When a variable or observable changes, the binding will be scheduled to change before
    // the next frame. There are times, however, when binding must be executed immediately.
    // To force execution, use the executePendingBindings() method.
    mBinding.executePendingBindings();
   }

   @Override
   public void onUploadClick(@NonNull FormData formData) {
    adapterListener.onUploadPic(getAdapterPosition(), formData);
   }
  }

  /**
   * Class used to pick date and time.
   */
  private class DateTimeViewHolder extends BaseViewHolder
  implements FormDateTimeViewModel.DateTimeListener {

   ItemDynamicFormDateTimeBinding mBinding;
   int mYear;
   int mMonth;
   int mDay;
   int mHour;
   int mMinute;
   int mSecond;
   FormDateTimeViewModel dateTimeViewModel;
   FormData data;

   DateTimeViewHolder(ItemDynamicFormDateTimeBinding mBinding) {
    super(mBinding.getRoot());
    this.mBinding = mBinding;
   }

   @Override
   public void onBind(int position) {
    data = formDataList.get(position);
    dateTimeViewModel = new FormDateTimeViewModel(data, this);
    mBinding.setViewModel(dateTimeViewModel);
    // Immediate Binding
    // When a variable or observable changes, the binding will be scheduled to change before
    // the next frame. There are times, however, when binding must be executed immediately.
    // To force execution, use the executePendingBindings() method.
    mBinding.executePendingBindings();
   }

   @Override
   public void dateClick() {
    Calendar calendar = Calendar.getInstance();
    mHour = calendar.get(Calendar.HOUR_OF_DAY);
    mMinute = calendar.get(Calendar.MINUTE);
    mSecond = 0;
    mYear = calendar.get(Calendar.YEAR);
    mMonth = calendar.get(Calendar.MONTH);
    mDay = calendar.get(Calendar.DAY_OF_MONTH);
    CommonUtils.openDatePicker(context, mYear, mMonth, mDay,
     0, 0, (view, year, monthOfYear, dayOfMonth) -> {
      String selectedDate = dayOfMonth + "-" + (monthOfYear + 1) + "-" + year;
      Calendar cal = Calendar.getInstance();
      cal.set(Calendar.YEAR, year);
      cal.set(Calendar.MONTH, monthOfYear);
      cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
      /*cal.set(Calendar.HOUR_OF_DAY, mHour);
      cal.set(Calendar.MINUTE, mMinute);
      cal.set(Calendar.SECOND, 0);*/

      dateTimeViewModel.getDate().set(DateTimeUtil.getParsedDate(cal.getTimeInMillis()));
      data.setEnteredValue(cal.getTimeInMillis() + "");
     });
   }

   @Override
   public void timeClick() {
    Calendar calendar = Calendar.getInstance();
    mHour = calendar.get(Calendar.HOUR_OF_DAY);
    mMinute = calendar.get(Calendar.MINUTE);

    CommonUtils.openTimePicker(context, mHour, mMinute,
     (view, hourOfDay, minute) -> {

      Calendar cal = Calendar.getInstance();
      cal.set(Calendar.YEAR, mYear);
      cal.set(Calendar.MONTH, mMonth);
      cal.set(Calendar.DAY_OF_MONTH, mDay);
      cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
      cal.set(Calendar.MINUTE, minute);
      cal.set(Calendar.SECOND, 0);
      dateTimeViewModel.getTime().set(DateTimeUtil.getParsedTime(cal.getTimeInMillis()));
      data.setEnteredValue(cal.getTimeInMillis() + "");
     });
   }
  }

  /**
   * Class used to pick date from & to .
   */
  private class DateRangeViewHolder extends BaseViewHolder
  implements FormDateRangeViewModel.DateRangeListener {
   ItemDynamicFormDateRangeBinding mBinding;
   FormDateRangeViewModel uploadViewModel;

   DateRangeViewHolder(ItemDynamicFormDateRangeBinding mBinding) {
    super(mBinding.getRoot());
    this.mBinding = mBinding;
   }

   @Override
   public void onBind(int position) {
    FormData data = formDataList.get(position);

    uploadViewModel = new FormDateRangeViewModel(data, this);
    mBinding.setViewModel(uploadViewModel);
    // Immediate Binding
    // When a variable or observable changes, the binding will be scheduled to change before
    // the next frame. There are times, however, when binding must be executed immediately.
    // To force execution, use the executePendingBindings() method.
    mBinding.executePendingBindings();
   }

   @Override
   public void dateViewClick(@NotNull View view) {
    // Get Current Date
    Calendar c = Calendar.getInstance();
    int mYear = c.get(Calendar.YEAR);
    int mMonth = c.get(Calendar.MONTH);
    int mDay = c.get(Calendar.DAY_OF_MONTH);
    //            int mHour = c.get(Calendar.HOUR_OF_DAY);
    //            int mMin = c.get(Calendar.MINUTE);
    CommonUtils.openDatePicker(context, mYear, mMonth, mDay,
     c.getTimeInMillis(), 0, (view1, year, monthOfYear, dayOfMonth) -> {
      //String selectedDate = dayOfMonth + "-" + (monthOfYear + 1) + "-" + year;
      Calendar cal = Calendar.getInstance();
      cal.set(Calendar.YEAR, year);
      cal.set(Calendar.MONTH, monthOfYear);
      cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);

      switch (view.getId()) {
       case R.id.tvDateRange1:
        uploadViewModel.getDate1().set(DateTimeUtil.getParsedDate(cal.getTimeInMillis()));
        formDataList.get(getAdapterPosition()).setMaxRange(cal.getTimeInMillis());
        break;
       case R.id.tvDateRange2:
        uploadViewModel.getDate2().set(DateTimeUtil.getParsedDate(cal.getTimeInMillis()));
        formDataList.get(getAdapterPosition()).setMinRange(cal.getTimeInMillis());
        break;
      }
     });

   }
  }

  /**
   * Class used to pick date
   */
  private class DateViewHolder extends BaseViewHolder
  implements FormDateViewModel.DateListener {
   ItemDynamicFormDateBinding mBinding;
   FormDateViewModel emptyItemViewModel;
   int mYear, mMonth, mDay;

   DateViewHolder(ItemDynamicFormDateBinding mBinding) {
    super(mBinding.getRoot());
    this.mBinding = mBinding;
   }

   @Override
   public void onBind(int position) {
    FormData data = formDataList.get(position);

    emptyItemViewModel = new FormDateViewModel(data, this);
    mBinding.setViewModel(emptyItemViewModel);
    // Immediate Binding
    // When a variable or observable changes, the binding will be scheduled to change before
    // the next frame. There are times, however, when binding must be executed immediately.
    // To force execution, use the executePendingBindings() method.
    mBinding.executePendingBindings();
   }

   @Override
   public void onDateClick() {
    Calendar calendar = Calendar.getInstance();
    mYear = calendar.get(Calendar.YEAR);
    mMonth = calendar.get(Calendar.MONTH);
    mDay = calendar.get(Calendar.DAY_OF_MONTH);
    CommonUtils.openDatePicker(context, mYear, mMonth, mDay,
     0, 0, (view, year, monthOfYear, dayOfMonth) -> {
      //                        String selectedDate = dayOfMonth + "-" + (monthOfYear + 1) + "-" + year;

      Calendar c = Calendar.getInstance();
      c.set(Calendar.YEAR, year);
      c.set(Calendar.MONTH, monthOfYear);
      c.set(Calendar.DAY_OF_MONTH, dayOfMonth);
      formDataList.get(getAdapterPosition()).setMaxRange(c.getTimeInMillis());
      emptyItemViewModel.getDate().set(DateTimeUtil.getParsedDate(c.getTimeInMillis()));

     });
   }
  }

/**
 * If hashMap is empty show empty view
 */
private class EmptyViewHolder extends BaseViewHolder
        implements FormEmptyItemViewModel.ClickListener {

    private ItemDynamicFormEmptyViewBinding mBinding;

    EmptyViewHolder(ItemDynamicFormEmptyViewBinding binding) {
        super(binding.getRoot());
        this.mBinding = binding;
    }

    @Override
    public void onBind(int position) {
        FormEmptyItemViewModel emptyItemViewModel = new FormEmptyItemViewModel(this);
        mBinding.setViewModel(emptyItemViewModel);
    }
}

/**
 * If view type is not handled then show this view
 */
private class UnknownViewHolder extends BaseViewHolder {

    UnknownViewHolder(ItemDynamicFormUnknownBinding unknownBinding) {
        super(unknownBinding.getRoot());
    }

    @Override
    public void onBind(int position) {

    }
}

如果您有任何疑問,請告訴我,Happy Coding:)

使 RecyclerView ViewModel 不可回收。 我認為recyclerview默認設置為刷新,因此,打亂項目例如

class YourViewModel extends RecyclerView.ViewHolder {

    YourViewModel (@NonNull View view) {
       super(view);

       // Add the line below
       this.setIsRecyclable(false);

     }
}

此外,您可以在填充項目之前使用 Collection.sort(items) 實現排序方法,因此即使視圖被回收,項目仍然保持排序(例如按 id)。

你可以試試:

@Override
public long getItemId(int position) {
    return position;
}

同時覆蓋:

@Override
public int getItemViewType(int position) {
    return position;
}

為 recyclerview 增加緩存的一種方法是:

recyclerView.setItemViewCacheSize(20)

您還可以借助 LinearLayoutManager 的方法calculateExtraLayoutSpace獲得額外空間。 我已經添加了文檔的鏈接。

或者,您可以使用:

setIsRecyclable(false);

但這超出了使用 RecyclerView 的目的。

您不應該使用hashCode()作為 ID,因為它不能保證是唯一的。 我的猜測是您的許多項目都返回相同的哈希值。 請嘗試為每個項目實現一個唯一 ID,並在您的getItemId()方法中使用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM