我有一个包含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行中显示的视图类型
答案 0 :(得分:2)
在Android中,适配器用于创建表示特定数据集的视图。您可以将适配器视为数据和显示之间的桥梁。
因此,ViewHolder是您在给定位置的数据的表示。由于视图通常比纯数据占用更多内存,因此RecyclerView
在滚动时重用它们。这就是为什么您无法检索与滚出屏幕的视图相关联的数据的原因:那些ViewHolder已被回收,之前的状态已丢失。
要解决此问题,我建议您执行以下步骤:
SparseArray<UserConfigurableParametersResponseMainItem1>
作为适配器的字段。此SparseArray将包含已由用户修改的模型对象的副本。对于每个有趣的更改,请调用holder.getAdapterPosition()
以检索此ViewHolder在数据集中的当前位置。使用position
检查SparseArray
中此位置是否存在对象。如果它不存在,请在listParams
的相同位置创建原始数据的副本。然后设置此对象的属性以反映用户所做的更改。
这个想法是维持一个&#34;缓存&#34;用户在适配器中进行的修改。这样,用户所做的修改就不会丢失。
在onBindViewHolder
中,从SparseArray中的给定position
检索数据。如果是null
,则表示未进行任何修改,您可以绑定listParams
的数据。否则,用户已进行了修改,您必须绑定它们而不是原始的。
创建方法UserConfigurableParametersResponseMainItem1 getModificationsForPosition(int position)
。此方法直接映射到SparseArray
中包含的数据。这样,调用Fragment
直接意识到如果返回的值不是null
则会发生修改。
点击&#34;保存&#34;按钮,使用for循环为适配器的每个有效位置调用getModificationsForPosition(i)
,检索所有已修改的对象,然后将它们保存在任何您想要的位置(SQLite或远程服务器)。
根据保存的更改刷新适配器的数据集。例如,您可以将listParams
中的数据替换为稀疏数组中的数据。当&#34; Save&#34;时,不要忘记清除稀疏阵列。按钮已被点击。
这种结构具有以下优点:
希望它有所帮助!