1

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.

Ani
  • 13
  • 4
  • Possible duplicate of [ListView - getView is called too much times](http://stackoverflow.com/questions/9157523/listview-getview-is-called-too-much-times) – Soham Aug 16 '16 at 05:26

1 Answers1

2

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)

TWL
  • 6,228
  • 29
  • 65