问题
I know about ListView recycling issue and try to keep my state in model, but it seems not to work. I've read many topics with the same problem, but their solutions dont work for me, or I do something wrong. When I scroll up and down the list view with radio group in initial state, nothing happens, that's right. But as soon as I set checked any radio button in any row and then scroll it up and down radio buttons become checked randomly.
RadioAdapter.java:
public class RadioAdapter extends ArrayAdapter<Question> {
List<Question> mSource;
static class ViewHolder {
TextView category = null;
TextView question = null;
RadioGroup rbGroup = null;
ViewHolder(View row) {
this.category = (TextView) row.findViewById(R.id.tvQuestionCategory);
this.question = (TextView) row.findViewById(R.id.tvQuestion);
this.rbGroup = (RadioGroup) row.findViewById(R.id.rgIteration);
}
}
private LayoutInflater mInflater;
public RadioAdapter(Context context, List<Question> mSource) {
super(context, R.layout.item_question, mSource);
mInflater = LayoutInflater.from(context);
this.mSource = mSource;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
View row = convertView;
if (row == null) {
row = mInflater.inflate(R.layout.item_question, null);
holder = new ViewHolder(row);
holder.rbGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group, int checkedId) {
//Get position of current group
Integer pos = (Integer) group.getTag();
switch (checkedId) {
case R.id.rbIterationYes:
//Check 'YES' and uncheck 'NO'
mSource.get(pos).setYesChecked(true);
mSource.get(pos).setNoChecked(false);
break;
case R.id.rbIterationNo:
//Vice versa
mSource.get(pos).setNoChecked(true);
mSource.get(pos).setYesChecked(false);
break;
}
}
});
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
holder.rbGroup.setTag(new Integer(position));
holder.category.setText(mSource.get(position).getCategory());
holder.question.setText(mSource.get(position).getDescription());
//If no one of buttons isn't checked
if (!mSource.get(position).isYesChecked() && !mSource.get(position).isNoChecked()) {
holder.rbGroup.clearCheck();
}else {
//We are supposing 'YES' is checked
int c = 0;
//Or 'NO' is checked
if (mSource.get(position).isNoChecked()){
c = 1;
}
//Set checked button
((RadioButton)holder.rbGroup.getChildAt(c)).setChecked(true);
}
return row;
}
}
Question.java:
public class Question {
private Integer id;
private String category;
private String description;
private boolean yesChecked;
private boolean noChecked;
/* Getters and setters */
}
item_question.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18dp"
android:id="@+id/tvQuestionCategory"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18dp"
android:id="@+id/tvQuestion"/>
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/rgIteration">
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:id="@+id/rbIterationYes"
android:text="@string/rbIterationYes"
android:textSize="16dp"/>
<RadioButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:id="@+id/rbIterationNo"
android:text="@string/rbIterationNo"
android:textSize="16dp" />
</RadioGroup>
</LinearLayout>
I hope you can help me find mistakes, because I am completely tired seeking solution. Thanks
回答1:
Before you are setting checked or unchecked to your RadioGroup
, you should disable the listener, like this. Hope this helps.
Change your adapter to this
public class RadioAdapter extends ArrayAdapter<Question> {
List<Question> mSource;
RadioGroup.OnCheckedChangeListener listener;
static class ViewHolder {
TextView category = null;
TextView question = null;
RadioGroup rbGroup = null;
ViewHolder(View row) {
this.category = (TextView) row.findViewById(R.id.tvQuestionCategory);
this.question = (TextView) row.findViewById(R.id.tvQuestion);
this.rbGroup = (RadioGroup) row.findViewById(R.id.rgIteration);
}
}
private LayoutInflater mInflater;
public RadioAdapter(Context context, List<Question> mSource) {
super(context, R.layout.item_question, mSource);
mInflater = LayoutInflater.from(context);
this.mSource = mSource;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
View row = convertView;
if (row == null) {
row = mInflater.inflate(R.layout.item_question, null);
holder = new ViewHolder(row);
listener = new RadioGroup.OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group, int checkedId) {
//Get position of current group
Integer pos = (Integer) group.getTag();
switch (checkedId) {
case R.id.rbIterationYes:
//Check 'YES' and uncheck 'NO'
mSource.get(pos).setYesChecked(true);
mSource.get(pos).setNoChecked(false);
break;
case R.id.rbIterationNo:
//Vice versa
mSource.get(pos).setNoChecked(true);
mSource.get(pos).setYesChecked(false);
break;
}
}
};
holder.rbGroup.setOnCheckedChangeListener(listener);
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
holder.rbGroup.setTag(new Integer(position));
holder.category.setText(mSource.get(position).getCategory());
holder.question.setText(mSource.get(position).getDescription());
//If no one of buttons isn't checked
holder.rbGroup.setOnCheckedChangeListener(null);
if (!mSource.get(position).isYesChecked() && !mSource.get(position).isNoChecked()) {
holder.rbGroup.clearCheck();
}else {
//We are supposing 'YES' is checked
int c = 0;
//Or 'NO' is checked
if (mSource.get(position).isNoChecked()){
c = 1;
}
//Set checked button
((RadioButton)holder.rbGroup.getChildAt(c)).setChecked(true);
}
holder.rbGroup.setOnCheckedChangeListener(listener);
return row;
}
}
回答2:
You can do like this override getItemId method and return your question id so you will able to identify each question and answer with id.
public class RadioAdapter extends ArrayAdapter<Question> {
List<Question> mSource;
static class ViewHolder {
TextView category = null;
TextView question = null;
RadioGroup rbGroup = null;
ViewHolder(View row) {
this.category = (TextView) row.findViewById(R.id.tvQuestionCategory);
this.question = (TextView) row.findViewById(R.id.tvQuestion);
this.rbGroup = (RadioGroup) row.findViewById(R.id.rgIteration);
}
}
private LayoutInflater mInflater;
public RadioAdapter(Context context, List<Question> mSource) {
super(context, R.layout.item_question, mSource);
mInflater = LayoutInflater.from(context);
this.mSource = mSource;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
View row = convertView;
if (row == null) {
row = mInflater.inflate(R.layout.item_question, null);
holder = new ViewHolder(row);
holder.rbGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
public void onCheckedChanged(RadioGroup group, int checkedId) {
//Get position of current group
//Integer pos = (Integer) group.getTag();
switch (checkedId) {
case R.id.rbIterationYes:
//Check 'YES' and uncheck 'NO'
mSource.get((int) getItemId(position)).setYesChecked(true);
mSource.get((int) getItemId(position)).setNoChecked(false);
break;
case R.id.rbIterationNo:
//Vice versa
mSource.get((int) getItemId(position)).setNoChecked(true);
mSource.get((int) getItemId(position)).setYesChecked(false);
break;
}
}
});
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
holder.rbGroup.setTag(new Integer(position));
holder.category.setText(mSource.get(position).getCategory());
holder.question.setText(mSource.get(position).getDescription());
//If no one of buttons isn't checked
if (!mSource.get((int) getItemId(position)).isYesChecked() && !mSource.get((int) getItemId(position)).isNoChecked()) {
holder.rbGroup.clearCheck();
} else {
//We are supposing 'YES' is checked
int c = 0;
//Or 'NO' is checked
if (mSource.get((int) getItemId(position)).isNoChecked()) {
c = 1;
}
//Set checked button
((RadioButton) holder.rbGroup.getChildAt(c)).setChecked(true);
}
return row;
}
@Override
public long getItemId(int position) {
return mSource.get(position).getId();
}
}
来源:https://stackoverflow.com/questions/35845816/radiogroup-doesnt-keep-properly-state-in-listview