Search code examples
androidlistviewonclicklistener

OnClickListener on Button in ListView changes multiple Items


so i declared a button for every item in the ListView but it happens that it responds to more Items then just the clicked one. For example if i push the button of the first button the 9th and 18th item are getting changed aswell. It would be awesome if you could help me with this one :) thanks in advance

This is the CusomtListAdapter which fills the ListView

    public class CustomListAdapter extends BaseAdapter {

    private ArrayList<Task> tasks;
    private LayoutInflater inflater = null;
    private Application application;

    public CustomListAdapter(Activity activity, Application application,
                             ArrayList<Task> tasks) {
        this.application = application;
        this.tasks = tasks;
        inflater = (LayoutInflater) application.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public static class ViewHolder {
        TextView lv_tv_description;
        TextView lv_tv_period;
        Button lv_bt_done;
        TextView lv_gone_pk;
        TextView lv_gone_group_pk;
        TextView lv_gone_description;
        TextView lv_gone_period;
        TextView lv_gone_period_kind;
        TextView lv_gone_time;
        TextView lv_gone_done;
    }

    @Override
    public int getCount() {
        return tasks.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(final int position, View vi, ViewGroup parent) {

        final ViewHolder viewHolder;

        if (vi == null) {
            vi = inflater.inflate(R.layout.listview, parent, false);
            viewHolder = new ViewHolder();

            viewHolder.lv_tv_description = (TextView) vi.findViewById(R.id.lv_tv_description);
            viewHolder.lv_tv_period = (TextView) vi.findViewById(R.id.lv_tv_period);
            viewHolder.lv_bt_done = (Button) vi.findViewById(R.id.lv_bt_done);

            viewHolder.lv_gone_pk = (TextView) vi.findViewById(R.id.lv_gone_pk);
            viewHolder.lv_gone_group_pk = (TextView) vi.findViewById(R.id.lv_gone_group_pk);
            viewHolder.lv_gone_description = (TextView) vi.findViewById(R.id.lv_gone_description);
            viewHolder.lv_gone_period = (TextView) vi.findViewById(R.id.lv_gone_period);
            viewHolder.lv_gone_period_kind = (TextView) vi.findViewById(R.id.lv_gone_period_kind);
            viewHolder.lv_gone_time = (TextView) vi.findViewById(R.id.lv_gone_time);
            viewHolder.lv_gone_done = (TextView) vi.findViewById(R.id.lv_gone_done);


            vi.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) vi.getTag();
        }

        viewHolder.lv_tv_description.setText(tasks.get(position).getDescription());
        viewHolder.lv_tv_period.setText(tasks.get(position).getPeriod_kind());

        viewHolder.lv_bt_done.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                DatabaseHandler dbhandler = new DatabaseHandler(application);


                View pk_view = (View) v.getParent().getParent().getParent();
                TextView textview_pk = ((TextView) pk_view.findViewById(R.id.lv_gone_pk));

                View parentView = (View) v.getParent().getParent();
                TextView textview1 = ((TextView) parentView.findViewById(R.id.lv_tv_description));
                TextView textview2 = ((TextView) parentView.findViewById(R.id.lv_tv_period));
                Button button = ((Button) parentView.findViewById(R.id.lv_bt_done));

                if (viewHolder.lv_bt_done.getText().toString().equalsIgnoreCase("done")) {
                    viewHolder.lv_tv_description.setPaintFlags(viewHolder.lv_tv_description.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
                    viewHolder.lv_gone_description.setPaintFlags(viewHolder.lv_gone_description.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
                    viewHolder.lv_bt_done.setText("UNDO");
                    viewHolder.lv_bt_done.setBackgroundResource(R.drawable.layout_rounded_background_accent);

                    notifyDataSetChanged();

                    dbhandler.updateDone(Integer.valueOf(textview_pk.getText().toString()), "true");
                } else if (viewHolder.lv_bt_done.getText().toString().equalsIgnoreCase("undo")) {
                    viewHolder.lv_tv_description.setPaintFlags(viewHolder.lv_tv_description.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
                    viewHolder.lv_gone_description.setPaintFlags(viewHolder.lv_gone_description.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
                    viewHolder.lv_bt_done.setText("DONE");
                    viewHolder.lv_bt_done.setBackgroundResource(R.drawable.layout_rounded_background);

                    notifyDataSetChanged();

                    dbhandler.updateDone(Integer.valueOf(textview_pk.getText().toString()), "false");
                }

                dbhandler.close();
            }
        });

        viewHolder.lv_gone_pk.setText(String.valueOf(tasks.get(position).getPk()));

        if (tasks.get(position).getDone().equalsIgnoreCase("true")) {
            viewHolder.lv_tv_description.setPaintFlags(viewHolder.lv_tv_description.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            viewHolder.lv_tv_period.setPaintFlags(viewHolder.lv_tv_description.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
            viewHolder.lv_bt_done.setText("UNDO");
            viewHolder.lv_bt_done.setBackgroundResource(R.drawable.layout_rounded_background_accent);
        }

        return vi;
    }}

and this is the matching layout file for all the items

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:focusable="false"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="70dp">

    <LinearLayout
        android:focusable="false"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:focusable="false"
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1">

            <RelativeLayout
                android:focusable="false"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1">

                <TextView
                    android:focusable="false"
                    android:id="@+id/lv_tv_description"
                    android:textSize="20dp"
                    android:textColor="@android:color/black"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_alignParentTop="true"
                    android:layout_marginTop="7dp"/>

            </RelativeLayout>

            <RelativeLayout
                android:focusable="false"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="2">

                <TextView
                    android:focusable="false"
                    android:id="@+id/lv_tv_period"
                    android:textColor="@android:color/black"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_alignParentBottom="true"/>

            </RelativeLayout>

        </LinearLayout>

        <RelativeLayout
            android:focusable="false"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="4">

            <Button
                android:id="@+id/lv_bt_done"
                android:text="DONE"
                android:focusable="false"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_alignParentTop="true"
                android:layout_marginTop="10dp"
                android:background="@drawable/layout_rounded_background"/>

        </RelativeLayout>

    </LinearLayout>

    <!-- invisible TextViews -->
    <TextView
        android:focusable="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/lv_gone_pk"
        android:visibility="visible"
        android:layout_alignParentRight="true"/>

    <TextView
        android:focusable="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/lv_gone_group_pk"
        android:visibility="visible"
        android:layout_alignParentRight="true"/>

    <TextView
        android:focusable="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/lv_gone_description"
        android:visibility="gone"
        android:layout_alignParentRight="true"/>

    <TextView
        android:focusable="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/lv_gone_period"
        android:visibility="gone"
        android:layout_alignParentRight="true"/>

    <TextView
        android:focusable="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/lv_gone_period_kind"
        android:visibility="gone"
        android:layout_alignParentRight="true"/>

    <TextView
        android:focusable="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/lv_gone_time"
        android:visibility="gone"
        android:layout_alignParentRight="true"/>

    <TextView
        android:focusable="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/lv_gone_done"
        android:visibility="gone"
        android:layout_alignParentRight="true"/>

</RelativeLayout>

if you need anything else please let me know in the comments :)


Solution

  • The View gets reused in the ListView via the second parameter (convertView) of the getView() method.

    From the documentation,

    convertView - The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view.

    So at any time, only the number of views (plus a couple more) that are visible on your device screen is available in memory. As you scroll the list, the views that go off the screen are reused for the items that are coming into the screen.

    In your case, the 1st, 9th item and 18th item are the same View being reused. That's why you are getting the changed View for the 9th and 18th item when you press the button only on the 1st item.

    Solution:

    When the button is pressed, add that state information in some data structure. For example, in an array of booleans, save true for the item whose button is in pressed state and false for other buttons.

    And in the getView() method, check the state of the button from that array of booleans and change the view respectively.