如何在循环播放视图中滚动浏览后的视图中的值

时间:2017-12-26 14:17:46

标签: android android-recyclerview android-viewholder

我有一个包含RecyclerView的片段。这个RecyclerView将包含几种不同类型的视图(EditText,Seekbar,CheckBox等),它将作为一种Form使用。我还有一个执行保存的按钮,它应该转到RecyclerView的每一行并获取用户输入的值。

我还有一个适配器可以根据我想在RecyclerView上添加的视图类型来扩展不同的布局。 在这个适配器中,我有一个“getValuesFromViews”方法,它根据视图类型读取用户输入。

public String getValuesFromViews(int position,ViewHolder vHolder){
 //...
}

在我的片段中,在For循环中,我在使用findViewHolderForAdapterPosition获取ViewHolder后调用此方法

我的问题是,当我滚动我的RecyclerView时,我丢失了ViewHolders以显示屏幕上未显示的位置,因此findViewHolderForAdapterPosition返回null。

如何从屏幕上未显示的视图中读取值?

修改 这是我的适配器(仍在使用它)。

public class ParamsAdapter extends RecyclerView.Adapter<ParamsAdapter.ViewHolder> {
    private final android.support.v4.app.FragmentManager fragmentManager;
    private final Fragment fragment;
    private Context context;
    private View view1;


    ParamsAdapter.ViewHolder viewHolder1;
    List<UserConfigurableParametersResponseMainItem1> listParams;

    public ParamsAdapter(Context context1, List<UserConfigurableParametersResponseMainItem1> list, android.support.v4.app.FragmentManager fmanager, Fragment frag){
        context = context1;
        listParams = list;
        fragmentManager = fmanager;
        fragment = frag;
    }

    public List<UserConfigurableParametersResponseMainItem1> getListParams() {
        return listParams;
    }

    public class ViewHolder extends RecyclerView.ViewHolder{

        @BindView(R.id.tv_param_title)
        TextViewMPOS tvParamTitle;
        @BindView(R.id.iv_question)
        ImageView ivQuestion;
        @Nullable @BindView(R.id.et_param)
        View param;
        @BindView(R.id.param_loader)
        AVLoadingIndicatorView loader;
        @BindView(R.id.iv_status)
        ImageView iv_status;
        @BindView(R.id.iv_error)
        ImageView iv_error;
        @BindView(R.id.tv_param_error)
        TextViewMPOS tvError;
        @BindView(R.id.iv_reset)
        ImageView ivReset;

        public ViewHolder(View v){
            super(v);
            ButterKnife.bind(this,v);

        }
    }

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

    @Override
    public ParamsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){

        view1 = createViews(parent,viewType);
        viewHolder1 = new ParamsAdapter.ViewHolder(view1);

        return viewHolder1;
    }

    private View createViews(ViewGroup parent, int viewType) {
        ConfigurableParameterWebControlCode op = listParams.get(viewType).getParamWbCntrlCd();
        switch (op){
            case NUMERO:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_num,parent,false);
            case DOUBLE:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_double,parent,false);
            case EMAIL:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_email,parent,false);
            case TEXTBOX:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_text,parent,false);
            case TEXAREA:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_textarea,parent,false);
            case SLIDER:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_slider,parent,false);
            case CHECKBOX:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_num,parent,false);
            case DROPDOWN:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_drop,parent,false);
            case RADIOBUTTON:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_num,parent,false);
            case DATA:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_data,parent,false);
            case DATAHORA:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_datahora,parent,false);
            case TEMPO:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_tempo,parent,false);
/*            case PHONE:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_phone,parent,false);*/
            case CHECKGROUP:
                return LayoutInflater.from(context).inflate(R.layout.adapter_param_checkgroup,parent,false);
        }

        return null;
    }

    @Override
    public void onBindViewHolder(final ParamsAdapter.ViewHolder holder, final int position){

        final int index = getLanguageIndex(position);
        holder.tvParamTitle.setText(listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(index).getLablTxt());
        holder.ivQuestion.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(context != null)
                    MyDialogBuilder.createSingleButtonDialog(context,R.drawable.ic_warningcor,listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(index).getHlprTxt(),R.string.ok,null,-1).show();
            }
        });
        holder.ivReset.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                clearView(holder,position);
            }
        });

        holder.iv_error.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(context != null)
                    MyDialogBuilder.createSingleButtonDialog(context,R.drawable.ic_errorcor,listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(index).getErrTxt(),R.string.ok,null,-1).show();
            }
        });


        switch (listParams.get(position).getParamWbCntrlCd()){

            case NUMERO:
            case DOUBLE:
            case EMAIL:
            case TEXTBOX:
            case TEXAREA:
            case TELEFONE:
                EditTextMPOS editTextAux = (EditTextMPOS)holder.param;
                if (editTextAux != null) {
                    editTextAux.setText(listParams.get(position).getParamVl());
                }
                break;
            case SLIDER:
                AppCompatSeekBar seekbarAux = (AppCompatSeekBar)holder.param;
                seekbarAux.setMax(Integer.parseInt(listParams.get(position).getParamVldtnMax()));
                seekbarAux.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                        holder.tvParamTitle.setText(listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(index).getLablTxt() +"   "+i);
                    }

                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {

                    }

                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {

                    }
                });
                break;
            case CHECKBOX:
                break;
            case DROPDOWN:
                break;
            case RADIOBUTTON:
                break;

            case DATA:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogDateNoHoursPicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"# ",0);
                        }
                    });
                }
                break;
            case DATAHORA:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogDatePicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"##",0);
                        }
                    });
                }
                break;
            case TEMPO:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogTimePicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"###",0);
                        }
                    });
                }
                break;
            case CHECKGROUP:
                LinearLayout linearLayout = (LinearLayout)holder.param;
                List<String> checkList = new ArrayList<String>(Arrays.asList(listParams.get(position).getParamVldtnRgExp().split(";")));
                for(int i=0;i<checkList.size();i++){
                    CheckBox checkBox = new CheckBox(context);
                    checkBox.setText(checkList.get(i));
                    LinearLayout.LayoutParams newParams = new LinearLayout.LayoutParams(
                            RelativeLayout.LayoutParams.WRAP_CONTENT,
                            RelativeLayout.LayoutParams.WRAP_CONTENT);
                        newParams.weight = 1;
                        checkBox.setLayoutParams(newParams);

                    linearLayout.addView(checkBox,i);
                }
                break;
        }
    }

    private void clearView(ViewHolder holder, int position) {
        switch (listParams.get(position).getParamWbCntrlCd()){
            case NUMERO:
            case DOUBLE:
            case EMAIL:
            case TEXTBOX:
            case TEXAREA:
            case TELEFONE:
                EditTextMPOS auxView = (EditTextMPOS)holder.param;
                if (auxView != null) {
                    auxView.setText("");
                    auxView.setHint(listParams.get(position).getDfltVl());
                }
                listParams.get(position).setUseDefault(true);
                break;
            case CHECKBOX:
                break;
            case DROPDOWN:
                break;
            case RADIOBUTTON:
                break;
            case DATA:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogDateNoHoursPicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"# ",0);
                        }
                    });
                }
                break;
            case DATAHORA:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogDatePicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"##",0);
                        }
                    });
                }
                break;
            case TEMPO:
                if (holder.param != null) {
                    holder.param.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            MyDialogBuilder.DialogTimePicker(context,fragmentManager,fragment, DatePickerFragment.DATE_END,"###",0);
                        }
                    });
                }
                break;
            case CHECKGROUP:
                break;
        }
    }

    private int getLanguageIndex(int position) {
        int index = 0;
        String lang = HelperSharedPreferences.getSharedPreferencesString(context,HelperSharedPreferences.LANG,"pt-PT");
        for (int i=0; i<listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().size();i++) {
            if(listParams.get(position).getUsrCnfgrblPrmtrsRspnItms().get(i).getLangCd().equals(lang)) {
                index = i;
                break;
            }
        }
        return index;
    }

    public String getValuesFromViews(int position,ViewHolder vHolder){
        String result = new String();
        if(listParams.get(position).isUseDefault()) {
            result = null;
        }
        else {
            switch (listParams.get(position).getParamWbCntrlCd()) {
                case NUMERO:
                case DOUBLE:
                case EMAIL:
                case TEXTBOX:
                case TEXAREA:
                case TELEFONE:
                    EditTextMPOS auxView = (EditTextMPOS) vHolder.param;
                    if (auxView != null) {
                        result = auxView.getText().toString();
                    }
                    break;
                case CHECKBOX:

                    break;
                case CHECKGROUP:
                    LinearLayout linearLayout = (LinearLayout)vHolder.param;
                    for(int i = 0;i<linearLayout.getChildCount();i++){
                        if(((CheckBox)linearLayout.getChildAt(i)).isChecked()){
                            result += ((CheckBox)linearLayout.getChildAt(i)).getText() + ";";
                        }
                    }
                    break;

            }
        }
        Logging.log("RESULT ",result);
        return result;
    }


    public void setStatus(final int position, ViewHolder vHolder,int status){
        if (status == 1) {
            vHolder.iv_status.setVisibility(View.VISIBLE);
            vHolder.iv_error.setVisibility(View.INVISIBLE);
            vHolder.param.setBackgroundResource(R.drawable.edit_text_background);
        } else if (status == 2) {
            vHolder.iv_status.setVisibility(View.INVISIBLE);
            vHolder.iv_error.setVisibility(View.VISIBLE);
            vHolder.param.setBackgroundResource(R.drawable.edit_text_error_background);
        } else {
            vHolder.iv_status.setVisibility(View.INVISIBLE);
            vHolder.iv_error.setVisibility(View.INVISIBLE);
            if (vHolder.param != null) {
                vHolder.param.setBackgroundResource(R.drawable.edit_text_background);
            }
        }
    }


    @Override
    public int getItemCount(){
        if(listParams != null)
            return listParams.size();
        else
            return 0;
    }

    public void update (List<UserConfigurableParametersResponseMainItem1> list){
        this.listParams.clear();
        this.listParams = list;
        setDataChanged();
    }

    public void setDataChanged(){
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                notifyDataSetChanged();
            }
        });
    }
}

并且我要创建它的Data是一系列类似的东西

    {

    "ParamCd":"xxxxxxx",
    "ParamVl":"xxxxxxx",
    "DfltVl":" ",
    "ParamVldtnRgExp":".*",
    "ParamWbCntrlCd":"EMAIL",   
    "ParamOrdr":54,
    "UsrCnfgrblPrmtrsRspnItms":[
        {
            "LangCd":"pt-PT",
            "LablTxt":"xxxxxxx",
            "HlprTxt":"xxxxxxxxxxxxxx",
            "ErrTxt":"xxxxxxxxxxxxxxxxxxxxx"
        },
        {
            "LangCd":"en-UK",
            "LablTxt":"xxxxxxx",
            "HlprTxt":"xxxxxxxxxxxxxx",
            "ErrTxt":"xxxxxxxxxxxxxxxxxxxxx"
        }
    ]
}

“ParamWbCntrlCd”字段用于定义RecyclerView行中显示的视图类型

1 个答案:

答案 0 :(得分:2)

在Android中,适配器用于创建表示特定数据集的视图。您可以将适配器视为数据显示之间的桥梁。

因此,ViewHolder是您在给定位置的数据的表示。由于视图通常比纯数据占用更多内存,因此RecyclerView在滚动时重用它们。这就是为什么您无法检索与滚出屏幕的视图相关联的数据的原因:那些ViewHolder已被回收,之前的状态已丢失。

要解决此问题,我建议您执行以下步骤:

  1. 创建SparseArray<UserConfigurableParametersResponseMainItem1>作为适配器的字段。此SparseArray将包含已由用户修改的模型对象的副本。
  2. 为ViewHolders中的每个View配置侦听器,其内容可以修改。
  3. 对于每个有趣的更改,请调用holder.getAdapterPosition()以检索此ViewHolder在数据集中的当前位置。使用position检查SparseArray中此位置是否存在对象。如果它不存在,请在listParams的相同位置创建原始数据的副本。然后设置此对象的属性以反映用户所做的更改。

    这个想法是维持一个&#34;缓存&#34;用户在适配器中进行的修改。这样,用户所做的修改就不会丢失。

    1. onBindViewHolder中,从SparseArray中的给定position检索数据。如果是null,则表示未进行任何修改,您可以绑定listParams的数据。否则,用户已进行了修改,您必须绑定它们而不是原始的。

    2. 创建方法UserConfigurableParametersResponseMainItem1 getModificationsForPosition(int position)。此方法直接映射到SparseArray中包含的数据。这样,调用Fragment直接意识到如果返回的值不是null则会发生修改。

    3. 点击&#34;保存&#34;按钮,使用for循环为适配器的每个有效位置调用getModificationsForPosition(i),检索所有已修改的对象,然后将它们保存在任何您想要的位置(SQLite或远程服务器)。

    4. 根据保存的更改刷新适配器的数据集。例如,您可以将listParams中的数据替换为稀疏数组中的数据。当&#34; Save&#34;时,不要忘记清除稀疏阵列。按钮已被点击。

    5. 这种结构具有以下优点:

      • 即使在ViewHolders被回收后,也会保留对视图的修改。
      • 每个位置都可以单独删除修改。
      • 您只保存已修改的数据,效率更高。

      希望它有所帮助!