The problem: When I clear and repopulate my ListView, if an item was previously checked, the item at the same index is checked as well. If the number of elements added to the adapter < the index of the previously checked item, nothing is checked.
I've tried blocking the use of convertView even if it exists but that has no effect. Strangely, when I stepped through the debugger to see what is going on and I see that repopulating the adapter results in one or more calls to setChecked(true) in CheckableLinearLayout. (I've included that stack trace below) Looking at the call stack for these invocations shows that its not any code that I wrote originating these calls. It's as though the ListView is remembering the index of the previous selection and restoring it on it's own.
My implementation: I've got a ListView set to singleSelection mode. I use a custom ArrayAdapter that has a getView(...) which returns instances of my CheckableListView implementation:
public class CheckableLinearLayout extends LinearLayout implements Checkable {
private boolean isChecked;
public CheckableLinearLayout(Context context) {
super(context);
}
public CheckableLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setChecked(boolean isChecked) {
this.isChecked = isChecked;
if(isChecked) {
setBackgroundColor(Color.DKGRAY);
} else {
setBackgroundColor(Color.BLACK);
}
}
@Override
public boolean isChecked() {
return isChecked;
}
@Override
public void toggle() {
setChecked(!isChecked);
}
}
My ArrayAdapter's getView implementation:
@Override
public View getView(int pos, View convertView, ViewGroup parent) {
LayoutInflater inf = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
CheckableLinearLayout row = (CheckableLinearLayout) convertView;
if (row == null) {
row = (CheckableLinearLayout) inf.inflate(R.layout.file_explorer_item, parent, false);
}
// I explicitly set checked to false, in case this was a convertView:
row.setChecked(false);
// population various elements of the view is done here
return row;
}
}
Any ideas?
PS. Here's the stack trace of one of the mystery calls to setChecked(true):
<1> main@830013232224, prio=5, in group 'main', status: 'RUNNING'
at my.package.CheckableLinearLayout.setChecked(CheckableLinearLayout.java:25)
at android.widget.ListView.setupChild(ListView.java:1834)
at android.widget.ListView.makeAndAddView(ListView.java:1765)
at android.widget.ListView.fillSpecific(ListView.java:1318)
at android.widget.ListView.layoutChildren(ListView.java:1636)
at android.widget.AbsListView.onLayout(AbsListView.java:1863)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1617)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1401)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486)
at android.widget.LinearLayout.onLayout(LinearLayout.java:1399)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.widget.FrameLayout.onLayout(FrameLayout.java:431)
at android.view.View.layout(View.java:11278)
at android.view.ViewGroup.layout(ViewGroup.java:4224)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1489)
at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4424)
at java.lang.reflect.Method.invokeNative(Method.java:-1)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
at dalvik.system.NativeStart.main(NativeStart.java:-1)
<10> Binder Thread #2@830019920808, prio=5, in group 'main', status: 'RUNNING'
at dalvik.system.NativeStart.run(NativeStart.java:-1)
<9> Binder Thread #1@830019917952, prio=5, in group 'main', status: 'RUNNING'
at dalvik.system.NativeStart.run(NativeStart.java:-1)
<8> FinalizerWatchdogDaemon@830019904352 daemon, prio=5, in group 'main', status: 'SLEEPING'
at java.lang.VMThread.sleep(VMThread.java:-1)
at java.lang.Thread.sleep(Thread.java:1031)
at java.lang.Thread.sleep(Thread.java:1013)
at java.lang.Daemons$FinalizerWatchdogDaemon.run(Daemons.java:213)
at java.lang.Thread.run(Thread.java:856)
<7> FinalizerDaemon@830019904008 daemon, prio=5, in group 'main', status: 'WAIT'
at java.lang.Object.wait(Object.java:-1)
at java.lang.Object.wait(Object.java:401)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:102)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:73)
at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:168)
at java.lang.Thread.run(Thread.java:856)
<6> ReferenceQueueDaemon@830019903648 daemon, prio=5, in group 'main', status: 'WAIT'
at java.lang.Object.wait(Object.java:-1)
at java.lang.Object.wait(Object.java:364)
at java.lang.Daemons$ReferenceQueueDaemon.run(Daemons.java:128)
at java.lang.Thread.run(Thread.java:856)
<5> Compiler@830019903408 daemon, prio=5, in group 'system', status: 'WAIT'
at dalvik.system.NativeStart.run(NativeStart.java:-1)
<3> Signal Catcher@830019902928 daemon, prio=5, in group 'system', status: 'WAIT'
at dalvik.system.NativeStart.run(NativeStart.java:-1)
<2> GC@830019902704 daemon, prio=5, in group 'system', status: 'WAIT'
at dalvik.system.NativeStart.run(NativeStart.java:-1)