I've run into a problem twice just recently. Though I'm getting around it I can't help but feel that it's a rather unconventional method and that there's a better one.
This app is an exercise in using different types of persistent storage. I have 1 table to store short notes. In a ListView
those notes are displayed along with the date they were created and a button to delete that note.
Somehow inside an anonymous class' method override declaration for View.OnClickListener.onClick
I am left unable to get an item's _id
. But I DO have the view and so I place an invisible text view into the layout and every time I bind that view I setText
to the _id
of the row that is associated with that item.
When the button is clicked the item will be deleted using the _id
from the invisible view. YAY it works, however, it seems a little weird to be doing it that way.
app/src/main/java/se/frand/app/onetableapp/DateListAdapter.java
@Override
public void bindView(final View view, final Context context, final Cursor cursor) {
...
viewHolder.deleteButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String where = MyContract.NoteEntry.COLUMN_NAME_ID + "=?";
// Retrieve the id of the row to delete from an invisible textview in the item layout
// view is from bindView
String[] args = new String[] {
""+((TextView)view.findViewById(R.id.note_id)).getText() };
context.getContentResolver().delete(
MyContract.NoteEntry.CONTENT_URI, where, args);
swapCursor(MainActivity.getLogTimes(context));
}
});
viewHolder.noteView.setText(cursor.getString(MainActivity.COL_DATETIME_NOTE));
// setText of invisible textView to the id from the cursor
viewHolder.invisibleView.setText(cursor.getString(MainActivity.COL_DATETIME_ID));
}
app/src/main/res/layout/list_item_selected_layout.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">
...
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/item_delete_button"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/note_id"
android:visibility="invisible"/>
</LinearLayout>
My question is, how would you retrieve the _id
?
Here's how I did it in the master branch originally, but it didn't work. I caught the bug when I was working on my first refactor.
String where = MyContract.DateEntry.COLUMN_NAME_ID + "=?";
String[] args = {""+cursor.getInt(MainActivity.COL_DATETIME_ID)};
db.delete(MyContract.DateEntry.TABLE_NAME, where, args);
The problem here is it always gets the first row's id and deletes that row. It appears cursor is starting at the front even though cursor.getString(MainActivity.COL_DATETIME_NOTE)
on the other side of the anonymous method is adding the correct data (not all items repeat the first row).
Below is an additional occurrence of me resolving the same problem in the same way.
I had hit this problem just two days prior doing a similar app.
In this app users can view a set of nutritional ingredient items for a given meal. Long clicking a ingredient item brings up an AlertDialog
with optional replacements. Clicking one should replace the ingredient_id
in a reference table with the _id
of the ingredient selected.
The same problem occurred here. When I selected a dialog choice the ingredient of the first item in the list would be replaced, not the ingredient that was clicked.
Below is the code where I display the AlertDialog
and handle the click of a dialog choice.
app/src/main/java/se/frand/app/dietplan/IngredientsActivity.java
builder.setTitle(R.string.pick_replace)
.setItems(ingredients, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int position) {
// Once again here is where I pull the _id from the view
String mealitemid = ""+((TextView) view.findViewById(R.id.meal_item_id)).getText();
SQLiteDatabase db = openOrCreateDatabase(MealsDbHelper.DATABASE_NAME,0,null);
ContentValues values = new ContentValues();
values.put(MealItemsContract.MealItemEntry.COL_NAME_INGREDIENT_ID, ids[position]);
int rows = db.update(
MealItemsContract.MealItemEntry.TABLE_NAME,
values,
MealItemsContract.MealItemEntry.COL_NAME_ID+"=?",
new String[] {mealitemid});
cursor = db.rawQuery(query, new String[]{meal_id});
adapter.swapCursor(cursor);
db.close();
}
});
builder.show();
I have a theory now as to why, before clicking and notifying the listener the cursor is entirely iterated through. Thus when clicked the cursor is in the position of beyond final, which it looks like in this behavior would be the same as the beginning.
So what do you say? How should I be getting these _id
values into an inner anonymous listener method declaration? I'd really appreciate any general code review, tips unrelated to this problem in particular.