Search code examples
javalistviewandroid-sqlitesimplecursoradapter

ListItem.onItemClickListener with CustomAdapter unresponsive


I have a custom list_item, and the listview it's in has an onItemClickListener that goes to a new Activity. The problem I'm facing is that the onItemClickListener is unresponsive due to it not being able to recognize the ID of the item clicked. I suspect this problem is originating from my CustomAdapter but I'm unsure as to what can be done to fix it. The logged ID is listed as:

D/ListDataActivity: onItemClick: You Clicked on android.database.sqlite.SQLiteCursor@22fda4b

ListDataActivity.java:

public class ListDataActivity extends AppCompatActivity {

private static final String TAG = "ListDataActivity";

DatabaseHelper mDatabaseHelper;
TextView mTaskName;
TextView mTaskDesc;
ArrayAdapter adapter;
CustomAdapter customAdapter;
private ListView mListView;
DatabaseHelper db = new DatabaseHelper(this);

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.list_layout);
    mListView = (ListView) findViewById(R.id.listView);
    mDatabaseHelper = new DatabaseHelper(this);
    mTaskDesc = (TextView) findViewById(R.id.task_desc);
    mTaskName = (TextView) findViewById(R.id.task_name);

    populateListView();
}
private void populateListView() {
    String[] fromColumns = mDatabaseHelper.databaseToStringArray();
    int[] toViews = new int[]{R.id.task_name, R.id.task_desc};
    Cursor cursor;
    cursor = mDatabaseHelper.getWritableDatabase().rawQuery(" SELECT * FROM " + mDatabaseHelper.TABLE_NAME + " WHERE 1 ", null);
    Log.d(TAG, "populateListView: Displaying data in the ListView.");
    SimpleCursorAdapter customAdapter = new CustomAdapter(this, R.layout.list_item, cursor, fromColumns, toViews,0);
    mListView.setAdapter(customAdapter);



    mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            String name = adapterView.getItemAtPosition(i).toString();
            Log.d(TAG, "onItemClick: You Clicked on " + name);
            Cursor data = mDatabaseHelper.getItemID(name);
            int priority = 10;
            int itemID = -1;
            while(data.moveToNext()){
                itemID = data.getInt(0);
            }
            if(itemID > -1){
                Log.d(TAG, "onItemClick: The ID is: " + itemID);
                Intent editScreenIntent = new Intent(ListDataActivity.this, EditDataActivity.class);
                editScreenIntent.putExtra("id",itemID);
                editScreenIntent.putExtra("name",name);
                editScreenIntent.putExtra("priority",priority);
                startActivity(editScreenIntent);
            }
            else{
                toastMessage("No ID associated with that name");
            }
        }
    });
}
private void toastMessage(String message){
    Toast.makeText(this,message, Toast.LENGTH_SHORT).show();
}

}

CustomAdapter.java:

public class CustomAdapter extends SimpleCursorAdapter {

private int layout;
private Context context;
private DatabaseHelper mDatabaseHelper;

public CustomAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
    super(context, layout, c, from, to, flags);
    this.layout = layout;
    this.context = context;
}

@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
    Cursor c = getCursor();

    final LayoutInflater inflater = LayoutInflater.from(context);
    View v = inflater.inflate(R.layout.list_item, parent, false);
    bindView(v, context, c);
    return v;
}

@Override
public void bindView(View v, Context context, Cursor c) {

    int taskNameColumn = c.getColumnIndex(mDatabaseHelper.COL2);
    int taskDescColumn = c.getColumnIndex(mDatabaseHelper.COL4);

    String mTaskName = c.getString(taskNameColumn);
    String mTaskDesc = c.getString(taskDescColumn);

    TextView taskName = (TextView) v.findViewById(R.id.task_name);
    if (taskName != null){
        taskName.setText(mTaskName);
    }
    TextView taskDesc = (TextView) v.findViewById(R.id.task_desc);
    if (taskDesc != null){
        taskDesc.setText(mTaskDesc);
    }
}

}

And here is my list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@color/colorWhite">

        <TextView
            android:id="@+id/task_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="55dp"
            android:layout_marginTop="25dp"
            android:text="TextView" />

        <View
            android:id="@+id/viewbutton"
            android:layout_width="16dp"
            android:layout_height="16dp"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="21dp"
            android:layout_marginTop="24dp"
            android:background="@layout/round" />

        <TextView
            android:id="@+id/task_desc"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/task_name"
            android:layout_alignParentStart="true"
            android:layout_alignParentTop="true"
            android:layout_marginStart="55dp"
            android:layout_marginTop="53dp"
            android:layout_marginBottom="10dp"
            android:focusable="false"
            android:text="Undefined"
            android:textStyle="bold" />


</RelativeLayout>

If you would like me to elaborate on any of this I would be happy to. Thanks in advance!


Solution

  • As you're using a CursorAdapter then l (the 4th parameter passed to the overidden onItemClick method) will be the id. This assumes that the _id column is an alias of the rowid (i.e. you have _id INTEGER PRIMARY KEY coded with or without AUTOINCREMENT).

    • NOTE the 4th parameter 'l', for other adapters (e.g. ArrayAdapter) will not be the id rather it is typically the position (as a long) and thus the same as the the third parameter.

    As such try Log.d(TAG, "onItemClick: You Clicked on " + name + " with an id of " + String.valueOf(l));

    name is showing as android.database.sqlite.SQLiteCursor@22fda4b because the underyling item, which is retrieved by getItem is the Cursor who's toString method will be the default inherited method that prints the reference to the object.

    You probably want something like :-

    mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            Intent editScreenIntent = new Intent(ListDataActivity.this, EditDataActivity.class);
            editScreenIntent.putExtra("id",l); //<<<<<<<<<< THE ID AS kindly supplied by the CursorAdapter
            editScreenIntent.putExtra("name",data.getString(data.getColumnIndex(mDatabaseHelper.COL2)));
            editScreenIntent.putExtra("priority",data.getColumnIndex(mDatabaseHelper.COL4));
            startActivity(editScreenIntent);
            }
        }
    });
    
    • However, you could easily (and arguably more correctly) just pass the id via the intent and then retrieve the data (name and priority) from the table in the invoked activity.
    • Note the above code is in-principle code, it has not been tested so may contain errors.
    • The Cursor should be positioned at the current row/respective row so need need to do any moves.