Ani Ani - 3 months ago 34
Android Question

Android ListView with Switch onCheckedListener weird

I am fairly new to android development and started a little app project. Now I have a problem I can't seem to be able to solve alone and found no solution in searching. So I hope you'll have an advice for me :)

I have a ListView with a template like this:


<Switch
android:id="@+id/trackingSwitch"
android:layout_columnSpan="1"
android:layout_alignParentLeft="true"
android:layout_row="0"
android:layout_column="0" />

<TextView
android:id="@+id/tvName"
android:layout_columnSpan="1"
android:text="Name"
android:textColor="#545454"
android:textSize="20dp"
android:layout_marginLeft="10dp"
android:layout_gravity="fill_horizontal"
android:layout_row="0"
android:layout_column="1" />

<TextView
android:id="@+id/tvTime"
android:layout_columnSpan="1"
android:text="Time"
android:textSize="15dp"
android:textStyle="italic"
android:layout_marginLeft="10dp"
android:layout_gravity="fill_horizontal"
android:layout_row="1"
android:layout_column="1" />
</GridLayout>


It works quite well, giving me a Switch Button and two Text fields right to it. Now I want to fill it with my object data, therefore I extend an ArrayAdapter and have this in getView():

@Override
public View getView(int position, View view, ViewGroup parent) {
// Get the data item for this position
final AniTracking aniTracking = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (view == null) {
view = LayoutInflater.from(getContext()).inflate(R.layout.tracking_list, parent, false);
}
// Lookup view for data population
Switch swActive = (Switch) view.findViewById(R.id.trackingSwitch);
TextView tvName = (TextView) view.findViewById(R.id.tvName);
TextView tvTime = (TextView) view.findViewById(R.id.tvTime);

// Populate the data into the template view using the data object
swActive.setChecked(aniTracking.isActive());
tvName.setText(aniTracking.getName());
tvTime.setText(aniTracking.getCurrentTrackingTime());


// attach listener to switch
swActive.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean newStatus) {
// switch set to active? start new AniTrackingPart
if (newStatus == true) {
AniTrackingPart aniTrackingPart = new AniTrackingPart();
aniTrackingPart.setStartTime(new DateTime());
AniTrackingManager.getInstance(getContext()).addAniTrackingPart(aniTracking, aniTrackingPart);
}
// set to inactive -> close current AniTrackingPart
else {
AniTrackingManager.getInstance(getContext()).closeActiveTrackingPart(aniTracking);
}
}
});

// Return the completed view to render on screen
return view;
}


My problem is the onCheckedChange Listener. When I append it the Switches behave weird, giving every item the state of true. I noticed the getView() method is called more than once for a position, do I need to care about that on my own?
I also have the feeling the listener might be triggered for position1 when I populate data for position2 (swActive.setChecked(aniTracking.isActive())), is that possible?

I am thankful for every help, this makes my progress stop for some days now.

Have a nice day,
Ani

Edit to clarify not being a duplicate question: The problem would also exists if the getView() wouldn't be called multiple times. As its being called for each item in the ListView the calls for position > 1 would already trigger my listener and give me false results.

TWL TWL
Answer

Your first problem is finding out why your notifyDataSetChanged is being called so many times. That will trigger getView for all visible views.

Your second problem, setChecked will trigger your setOnCheckedChangeListener

You can avoid that by using setOnClickListener instead:

    switch.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (switch.isChecked()) {

            } else {

            }
        }
    });

to make sure it's only called when it's touched, not by any ui-induced change.

(you'll also need to change your switch to final Switch)