Java Android RecyclerView项目在滚动中随机移动

Java Android RecyclerView项目在滚动中随机移动,java,android,android-recyclerview,Java,Android,Android Recyclerview,my multiple view type RecyclerView Adapter的项目/单元格在滚动条上进行随机移动。我列举了以下所有可能的解决方案,但没有一个有效 一, 增加了RecyclerView的缓存 如果有人有任何解决方案,请分享 我的适配器类 public class FormAdapter extends RecyclerView.Adapter<BaseViewHolder> { private Context mContext; private List&l

my multiple view type RecyclerView Adapter的项目/单元格在滚动条上进行随机移动。我列举了以下所有可能的解决方案,但没有一个有效

一,

  • 增加了RecyclerView的缓存
  • 如果有人有任何解决方案,请分享

    我的适配器类

    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);
    }
    
    公共类FormAdapter扩展了RecyclerView.Adapter{
    私有上下文;
    私有列表数据集;
    公共FormAdapter(上下文){
    mContext=上下文;
    mDataset=newarraylist();
    setHasStableIds(true);
    }
    公共列表getDataset(){
    返回mDataset;
    }
    public OnFormElementValueChangedListener getValueChangeListener(){
    返回链接器;
    }
    @凌驾
    public int getItemCount(){
    返回mDataset.size();
    }
    @凌驾
    public int getItemViewType(int位置){
    返回mDataset.get(position.getType();
    }
    @凌驾
    公共长getItemId(int位置){
    //返回super.getItemId(位置);
    返回mDataset.get(position.getBaseFormElementId();
    }
    @非空
    @凌驾
    public BaseViewHolder onCreateViewHolder(视图组父级,int-viewType){
    //根据标题或元素类型获取布局
    LayoutInflater充气器=LayoutInflater.from(parent.getContext());
    观点五;
    开关(视图类型){
    案例BaseFormElement.TYPE_标题:
    v=充气机充气(R.layout.form\u element\u标题,父项,false);
    返回新的FormElementHeader(v);
    case BaseFormElement.TYPE\u EDIT\u文本:
    v=充气机充气(R.layout.form_元素,父元素,假);
    返回新FormElementEditTextViewHolder(v,新FormItemEditTextListener(this));
    case BaseFormElement.TYPE\u PICKER\u日期:
    v=充气机充气(R.layout.form_元素,父元素,假);
    返回新的FormElement PickerDateViewHolder(v、McContext、this);
    案例BaseFormElement.TYPE\u选取器\u时间:
    v=充气机充气(R.layout.form_元素,父元素,假);
    返回新的FormElement PickerTimeViewHolder(v、McContext、this);
    case BaseFormElement.TYPE_PICKER_SINGLE:
    v=充气机充气(R.layout.form_元素,父元素,假);
    返回新的FormElementPickerSingleViewHolder(v,mContext,this,new FormItemEditTextListener(this));
    case BaseFormElement.TYPE\u PICKER\u MULTI:
    v=充气机。充气(R.layout.formelementlabel,父项,false);
    返回新的FormElement PickerMultiViewHolder(v、mContext、this);
    case BaseFormElement.TYPE_IMAGE_备注:
    v=充气机。充气(R.layout.formelementlabel,父项,false);
    返回带有RemarksViewHolder的新FormElement图像(v、McContext、this);
    case BaseFormElement.TYPE_开关:
    v=充气机充气(R.layout.form\u element\u开关,父级,错误);
    返回新的FormElementSwitchViewHolder(v、mContext、this);
    case BaseFormElement.TYPE_段:
    v=充气机充气(R.layout.form\u element\u开关,父级,错误);
    返回新的FormElementSwitchViewHolder(v、mContext、this);
    case BaseFormElement.TYPE_标签:
    v=充气机。充气(R.layout.formelementlabel,父项,false);
    返回新的FormElementLabelViewer文件夹(v,单击列表器);
    case BaseFormElement.TYPE_图像:
    v=充气机。充气(R.layout.formelementlabel,父项,false);
    返回新的FromElementImageViewHolder(v,mContext,this);
    case BaseFormElement.TYPE_视频:
    v=充气机。充气(R.layout.formelementlabel,父项,false);
    返回新的FormElementVideoViewHolder(v、McContext、this);
    案例BaseFormElement.DIALOG\u列表:
    v=充气机。充气(R.layout.form\u element\u mmv,父项,false);
    返回新的FormElementDialogListViewHolder(v、McContext、this);
    case BaseFormElement.TYPE_滑块:
    v=充气机。充气(R.layout.formelementlabel,父项,false);
    返回新的FormElementSliderViewHolder(v,mContext,this);
    违约:
    v=充气机充气(R.layout.form_元素,父元素,假);
    返回新FormElementEditTextViewHolder(v,新FormItemEditTextListener(this));
    }
    }
    @凌驾
    公共无效onBindViewHolder(BaseViewHolder,最终int位置){
    //获取当前对象
    BaseFormElement currentObject=mDataset.get(位置);
    holder.bind(位置、当前对象、mContext);
    }
    

    }

    使RecyclerView视图模型不可回收。我认为默认情况下,recyclerview设置为刷新,因此,对项目进行洗牌 比如说

    class YourViewModel extends RecyclerView.ViewHolder {
    
        YourViewModel (@NonNull View view) {
           super(view);
    
           // Add the line below
           this.setIsRecyclable(false);
    
         }
    }
    
    此外,您还可以在填充项之前使用Collection.sort(项)实现排序方法,因此即使视图被回收,项仍然保持排序(例如按id)。

    您可以尝试:

    @Override
    public long getItemId(int position) {
        return position;
    }
    
    还覆盖:

    @Override
    public int getItemViewType(int position) {
        return position;
    }
    
    增加recyclerview缓存的一种方法是:

    recyclerView.setItemViewCacheSize(20)
    
    您还可以借助LinearLayoutManager的方法获得额外的空间。我已经添加了文档的链接

    或者,您可以使用:

    setIsRecyclable(false);
    

    但是它超出了使用RecyclerView的目的。

    您不应该使用
    hashCode()
    作为ID,因为它不能保证是唯一的! 我猜您的许多项目都返回相同的哈希值。
    请尝试为每个项目实现一个唯一的ID,并在您的
    getItemId()
    方法中使用它。

    我已经研究过这种类型的
    RecyclerView
    ,下面是与多个
    视图类型一起使用的
    DynamicAdapter
    类。我希望你能弄清楚如何使用它

        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) {
    
        }
    }
    
    public类DynamicAdapter扩展了RecyclerView.Adapter{
    私有静态最终字符串标记=“DynamicAdapter”;
    私有静态最终int视图_EMPTY=0;
    私有静态最终整型视图\编辑\文本=1;
    私有静态最终int视图_签名=2;
    私有静态最终int视图_UPLOAD=3;
    私有静态最终整数视图\日期\时间=4;
    私有静态最终整数视图\日期\范围=5;
    私有静态最终整数视图\u日期=
    
        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) {
    
        }
    }