Piovezan
Piovezan

Reputation: 3223

Android onListItemClick() appears to be acting upon more than one list item

I have a ListActivity. My onListItemClick() method is expected to update a TextView inside the clicked item with the value of the clicked position (e.g. if I click the third item, it appears "Clicked position = 2", considering the 0-indexed item list). However, it appears to be updating more than one item (although the debugger steps through the method only once). Sometimes other glitches happen, such as the clicked item "Clicked position" text disappearing or its content changing as I scroll through the list. It is a strange behavior which can be reproduced with a simple project setup as below. Maybe a problem with my BaseAdapter?

EventList.java:

package com.example.listactivitytest;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;

public class EventList extends ListActivity {

    private List<String> mEventList = null;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mEventList = new ArrayList<String>();
        for (int i = 0; i < 200; i++) {
            mEventList.add("Position = " + i);
        }
        setListAdapter(new EventListAdapter(mEventList));
    }

    protected void onListItemClick(ListView l, View v, int position, long id) {

        TextView textView = (TextView)(v.findViewById(R.id.textClickedPosition));
        String clickedPosition = "Clicked position = " + position;
        textView.setText(clickedPosition);
    }
}

EventListAdapter.java:

package com.example.listactivitytest;

import java.util.ArrayList;
import java.util.List;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class EventListAdapter extends BaseAdapter {

    private List<String> eventList = new ArrayList<String>();

    public EventListAdapter() {
    }

    public EventListAdapter(List<String> eventList) {
        this.eventList = eventList;
    }

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

    @Override
    public Object getItem(int index) {
        return eventList.get(index);
    }

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

    @Override
    public View getView(int index, View view, ViewGroup parent) {
        if (view == null) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            view = inflater.inflate(R.layout.line_event_list, parent, false);
        }

        String event = eventList.get(index);

        TextView textView = (TextView) view.findViewById(R.id.textPosition);
        textView.setText(event);

        return view;
    }

    public List<String> getEventList() {
        return eventList;
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" >
    </ListView>

    <TextView android:id="@android:id/empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="Empty list"
        android:layout_weight="1" />

</LinearLayout>

line_event_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="3dp"
    android:orientation="vertical"
    android:background="#ffffff" >

    <TextView android:id="@+id/textPosition"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView android:id="@+id/textClickedPosition"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.listactivitytest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.listactivitytest.EventList"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Upvotes: 0

Views: 307

Answers (1)

Sam
Sam

Reputation: 86948

ListViews reuse their row layouts because it is more efficient than having a unique layout for each row. (10 layouts is faster than 10,000.) So you need to change the data set powering the Adapter rather than the TextView itself. First save new EventListAdapter() as a field variable, call it mAdapter, then try:

protected void onListItemClick(ListView l, View v, int position, long id) {
    String clickedPosition = "Clicked position = " + position;
    mAdapter.getEventList().set(position, clickedPosition);
    mAdapter.notifyDataSetChanged();
}

You should watch the Google I/O presentation Turbo Charge your UI to learn why ListViews do this and how to take advantage of this feature. (For instance a ViewHolder will help.)

Upvotes: 1

Related Questions