I have a ListView which uses a custom adapter as shown:
private class CBAdapter extends BaseAdapter implements OnCheckedChangeListener{
Context context;
Your code from the answer works but is inefficient(you can actually see this, just scroll the ListView
and check the Logcat
to see the garbage collector doing it's work). An improved getView
method which will recycle views is the one below:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout view = (LinearLayout) convertView;
if (view == null) {
view = (LinearLayout) inflater.inflate(R.layout.record_view_start, parent, false);
}
TextView tv = (TextView) view.findViewById(R.id.engName);
tv.setText(getItem(position));
CheckBox cBox = (CheckBox) view.findViewById(R.id.checkBox1);
cBox.setTag(Integer.valueOf(position)); // set the tag so we can identify the correct row in the listener
cBox.setChecked(mChecked[position]); // set the status as we stored it
cBox.setOnCheckedChangeListener(mListener); // set the listener
return view;
}
OnCheckedChangeListener mListener = new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mChecked[(Integer)buttonView.getTag()] = isChecked; // get the tag so we know the row and store the status
}
};
Regarding your code from your question, at first I thought it was wrong because of the way you setup the rows but I don't see why the adapter will have that behavior as you detached the row view from the list. Also, I even tested the code and it works quite well regarding CheckBoxes
(but with very poor memory handling). Maybe you're doing something else that makes the adapter to not work?
Let me first say that you have thrown away one of the main benefits of using an adapter: Reusable views. Holding a hard reference to each created View
holds a high risk of hitting the memory ceiling. You should be reusing convertView
when it is non-null, and creating your view when convertView
is null. There are many tutorials around which show you how to do this.
Views used in an adapter typically have an OnClickListener
attached to them by the parent View
so that you can set a OnItemClickListener
on the ListView
. This will supersede any touch listeners on the individual views. Try setting android:clickable="true"
on the CheckBox
in XML.
This may not be the most elegant or efficient solution but it works for my situation. For some reason attempting to reuse the views either from an array of views or using convertView makes every thing go wobbley and the CheckBoxes fail to respond.
The only thing that worked was creating a new View everytime getView() is called.
public View getView(final int position, View convertView, ViewGroup parent) {
LinearLayout view;
view=(LinearLayout)inflater.inflate(R.layout.record_view_start,null);
TextView tv=(TextView)view.findViewById(R.id.engName);
tv.setText(englishNames[position]);
CheckBox cBox=(CheckBox)view.findViewById(R.id.checkBox1);
cBox.setChecked(checked[position]);
cBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
checked[position]=isChecked;
}
});
return view;
}
Finding this solution was also hampered by the fact that I was calling a separately defined onCheckedChangedListener, that then identified which CheckBox by id, rather than having a new listener for each CheckBox.
As yet I haven't marked this as the correct answer as I'm hoping that others may have some input regarding the rather wasteful rebuilding the view every time.