I created a program that has custom ListView with ToggleButton on each view then encountered onCheckedChanged() to be called whenever I scroll even I didn't click it and returns the opposite value of its current state.
In my listAdapter, I have below getView() function. Notice that I've added logger.
When the app runs (see Image 1), you'll see list of different applications from browser to email (after clock). Notice that the browser's ToogleButton is ON. Base on the logs below, all list item that is currently seen on the screen called getView() and NOT all list items.
getView: com.android.browser
getView: com.android.calculator2
getView: com.android.calendar
getView: com.android.chrome
getView: com.android.contacts
getView: com.android.deskclock
getView: com.android.email
When you scroll the ListView, it will call getView() again for the new list items that are seen on the screen. See Image 2, I scrolled down the screen to see Gallery and Camera. In the logs, it called the getView() for the two (2) newly seen list items; called onCheckChanged() of the Browser even though I'm not clicking it and returns false (opposite of the earlier state).
**SCROLLS DOWN
getView: com.android.gallery3d
getView: com.android.hwcamera
onCheckedChanged: com.android.browser=false
When I scrolled up again, you'll notice that it called again the getView() for the Browser; and called the onCheckChanged() of the Camera which returns true (opposite of earlier state).
**SCROLLS UP
getView: com.android.browser
onCheckedChanged: com.android.hwcamera=true
I noticed that whenever I scroll, the first item that was removed from screen (in the Image 1, it's the Browser; while in Image 2, it's the Camera and ignored Gallery) calls onCheckedChanged() returning the opposite value of ToggleButton's current state.
Now, even when you scroll it, you'll only get the right state of ToggleButton when it is clicked.
In my listAdapter, I have below getView() function. Notice that I've added logger.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ListModel model = list.get(position);
System.out.print("getView: "+ model.getPackageName());
Holder holder = (Holder)view.getTag();
// some other source here that I removed
holder.toggleBtn.setChecked(model.getStatus());
holder.toggleBtn.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
System.out.print("onCheckedChanged: "+ model.getPackageName()+"="+isChecked);
}
});
holder.index = model.getIndex();
return view;
}
When the app runs (see Image 1), you'll see list of different applications from browser to email (after clock). Notice that the browser's ToogleButton is ON. Base on the logs below, all list item that is currently seen on the screen called getView() and NOT all list items.
![]() |
| Image 1: Screen is loaded from Browser to Email, though only a part of Email is seen. |
getView: com.android.calculator2
getView: com.android.calendar
getView: com.android.chrome
getView: com.android.contacts
getView: com.android.deskclock
getView: com.android.email
When you scroll the ListView, it will call getView() again for the new list items that are seen on the screen. See Image 2, I scrolled down the screen to see Gallery and Camera. In the logs, it called the getView() for the two (2) newly seen list items; called onCheckChanged() of the Browser even though I'm not clicking it and returns false (opposite of the earlier state).
![]() |
| Image 2: Scrolled down up to Camera |
getView: com.android.gallery3d
getView: com.android.hwcamera
onCheckedChanged: com.android.browser=false
When I scrolled up again, you'll notice that it called again the getView() for the Browser; and called the onCheckChanged() of the Camera which returns true (opposite of earlier state).
**SCROLLS UP
getView: com.android.browser
onCheckedChanged: com.android.hwcamera=true
I noticed that whenever I scroll, the first item that was removed from screen (in the Image 1, it's the Browser; while in Image 2, it's the Camera and ignored Gallery) calls onCheckedChanged() returning the opposite value of ToggleButton's current state.
Solution:
Use onClick() instead of onCheckedChanged(). To get the current state, cast the view to ToggleButton and call isChecked(). See below:holder.toggleBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Boolean isChecked = ((ToggleButton)view).isChecked();
model.setStatus(isChecked);
}
});
Now, even when you scroll it, you'll only get the right state of ToggleButton when it is clicked.



Post a Comment