I have a ListView backed by a SQLite db table which displays a song title (TextView) and a button (ImageButton) in the list item XML for each row. I setup an onClick() event for the button to take action on the song on the row they clicked on.
The ListView correctly displays all contents from the db table using a SimpleCursorAdapter.
Here's the question: when I click on the ImageButton it correctly calls the onClick event for the button with parameter (View view); how do I get to the Cursor row data for the row in which the button was clicked from the View passed into the event? I need the row _ID value in order to act on the correct song. I also have access to the dbAdapter in a Class field if I can get there from that object.
Notes: When I add an ImageButton to the Item List the onItemClickListener no longer fires if I click on the row containing the song or on the button.
And please, if there is a better design pattern to give the user the functionality of selecting a ListView item and performing an action on it, let me know. My intention is to eventually add 2-3 buttons per row for Delete, Info, Play, etc.
// Load ListView with previously downloaded files
dbHelper = new DBHelper(this);
// Create Cursor holding db data
Cursor cursor = dbHelper.fetchData();
// Map db columns to view ids
String[] columns = new String[]{
DBContract.Songs.COLUMN_NAME_NAME,
DBContract.Songs.COLUMN_NAME_LOADED_DATETIME
};
int[] to = new int[]{
R.id.songName,
R.id.songDateLoaded
};
// Create the dbAdapter
dbAdapter = new SimpleCursorAdapter(this, R.layout.songs, cursor, columns, to, 0);
// Assign the adapter to the ListView
ListView listView = findViewById(R.id.songsListView);
listView.setAdapter(dbAdapter);
// Anonymous OnItemClickListener
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {...
With Mike's persistent and patient assistance, I implemented the solution below.
The key is using a setViewBinder() on the SimpleCursorAdapter and then assigning the db row key to the Tag property of the ImageButton. Then, in XML, define an onClick() event and in that event, you now have access to the db row key from the view.getTag() method.
// Bind the Cursor record _ID to the ImageButton Tag property;
// So when it is called, we can delete the record with the Tag property value.
dbAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int i) {
if (view.getId() == R.id.songName) {
final long id = cursor.getLong(cursor.getColumnIndex(DBContract.Songs._ID));
final ImageButton delete = ((View)view.getParent()).findViewById(R.id.deleteSongButton);
delete.setTag(id);
}
return false;
}
});
public void DeleteSong(View view) {
final long id = (long) view.getTag();
dbHelper.RemoveSong(id);
dbHelper.fetchSongsAndUpdateAdapter(dbAdapter);
Toast.makeText(this, "Song removed!", Toast.LENGTH_LONG).show();
}
Thanks Mike!
Related
I have created a list view which shows the data from a database. In each row of the ListView I have added a CheckBox, a button to delete it and another to edit it.
My problem is to get the id over the row, in which a button is clicked and how to convert and use that id for my sqlite database command ?
Setting a long click listener has been a bit trouble since the rows do not respond to long click when there is a CheckBox in them , so i want the buttons to exist and function.
Thanks
At first i describe the structure of the codes and then the solution i found.
the application consist of a main activity which contains the ListView. Then there is a class of SqliteOpenHelper which handles the database and there is a TaskProvider class containing the setter and getter methods of variables in the database and a TaskAdapter which is the custom adapter for the ListView.
The problem that i was facing was the fact that i couldn't address a specific row by a button existed in that row. Here is how i did it :
first in the SqliteOpenHelper class, a method is created to contain the where clause and the SqliteDataBase.delete method
public void deleteTask (SQLiteDatabase db , String deleted){
String selection = Contracts.achieveTaskClass.ID+" LIKE ?";
String[] selectionArgs = {deleted};
db.delete(Contracts.achieveTaskClass.ACHIEVETASK_TABLE,selection,selectionArgs);
}
Then in the getView method of adapter class , the button which is set to delete the row is found and the following setOnClickListener is added:
objectHolder.taskDeleteButton = (Button) row.findViewById(R.id.list_view_delete_button);
objectHolder.taskDeleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String deleted;
deleted = ((TaskProvider) getItem(position)).getId();
Sqldb sqldb = new Sqldb(getContext());
SQLiteDatabase db = sqldb.getReadableDatabase();
sqldb.deleteTask(db,deleted);
}
});
I can't get this working. I want the item from list view to be deleted when I click on the button. But I really don't know how to implement this.
Here is my adapter
public class PersonalRecordsAdapterDialog extends CursorAdapter {
public PersonalRecordsAdapterDialog(Context context, Cursor c) {
super(context, c);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(context).inflate(R.layout.list_view_personal_layout, parent, false);
}
#Override
public void bindView(View view, Context context, final Cursor cursor) {
final DatabaseAdapter db = new DatabaseAdapter(context);
TextView weightTV = (TextView) view.findViewById(R.id.weight_tv);
TextView dateTV = (TextView) view.findViewById(R.id.date_tv);
final Button deleteRecord = (Button) view.findViewById(R.id.delete_record);
final String id = cursor.getString(cursor.getColumnIndex(DatabaseAdapter.DatabaseHelper.COL_1));
String weight = cursor.getString(cursor.getColumnIndex(DatabaseAdapter.DatabaseHelper.COL_3));
String date = cursor.getString(cursor.getColumnIndex(DatabaseAdapter.DatabaseHelper.COL_4));
weightTV.setText(weight);
dateTV.setText(date);
deleteRecord.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
db.remove(Integer.parseInt(id));
notifyDataSetChanged();
}
});
}
}
and here is my ListView
AlertDialog.Builder builder = new AlertDialog.Builder(holder.mContext);
View dialogView = View.inflate(holder.mContext,R.layout.dialog, null);
ListView myList = (ListView) dialogView.findViewById(R.id.dialog_list_view);
Cursor cursor = holder.myDb.getRows(exercise[position]);
PersonalRecordsAdapterDialog adapter = new PersonalRecordsAdapterDialog(holder.mContext,cursor);
myList.setAdapter(adapter);
builder.setView(dialogView)
.setTitle("History of your " + exercise[position].toLowerCase() + " records")
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int id) {
// sign in the user ...
}
});
AlertDialog b = builder.create();
b.show();
Thank you for your help
Remove the item from your model when onClick happens n call notifyDatasetChanged() for the same adapter
and in your case you are passing cursor directly to your custom adapter which is a very bad practice as in this case your connection with the db will stay open and can lead to Memory and DB issues
So you can create your own model (ArrayList) , get values from cursor, add them into your model,Close your db connection and pass that model to your adapter. and to remove a particular item remove that from your model and call notifyDatasetChanged().(Note: Removing from model will only remove the data from list but not from db. In case you want to delete that data from your db, you also have to execute Delete Query )
for this : I don't want to delete it when I click on ListView item. I want to delete it only when I click on button in ListView item
Go to your adapter class.. get the object instance over there in OnGetView(...) method and the the onClickListener for the same over there.
To delete row from DB you can use a unique id from db table like this
public void delete_byID(int id){
sqLiteDatabase.delete(MYDATABASE_TABLE, KEY_ID+"="+id, null);
}
Where MYDATABASE_TABLE is your table to delete from.
KEY_ID is the name of the coloumn to put where condition.
id is the unique id associated with the row you want to delete
So in this case you will not need the cursor to delete a particular record
The reason that bindView method doesn't refresh by the db change is :
The cursor is steel the old cursor .
You need to requery the data base get new cursor and then
Call adapter.change cursor(passHereTheNewCursor)
Adding to above answer by Nitesh - To delete item from listview on button click, Either 1. first you need to delete item from listview's adapter like below -
deleteButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Object objToRemove = adapter.getItem([POSITION]);
adapter.remove(objToRemove);
}
}
or 2. you can delete this item from your arrayList & call notifyDataSetChanged().
But this will not delete from database. you have to implement delete query for it.
and yes as above said -
in your case you are passing cursor directly to your custom adapter which is a very bad practice as in this case your connection with the db will stay open and can lead to Memory and DB issues.
I've created a ListView and bind it to an adaptor to display data from a table. It works great. I can select on a row and it display the product name that I'm selecting. Now I've added an ImageView in the layout that will act as delete buttons on each row. My problem is I can't figure out how to add the code to make it so that when a user select the ImageView (delete button), it will delete the row. I've searched and found a lot of articles on this topic and tried a lot of them and none really work my code. Do I need to create a getView function? Also I've tried inserting the getTag(), but I couldn't make it work. Can you help me with a sample code that may work with my simple code or point me to the right direction? Here is my code:
private void displayListView() {
prodinputHelper = new DBAdaptorProductInput(this);
prodinputHelper.open();
Cursor cursor = prodinputHelper.fetchAllProductInput();
// The desired columns to be bound
String[] columns = new String[] {
DBAdaptorProductInput.KEY_PRODUCTTYPE,
DBAdaptorProductInput.KEY_PRODUCTNAME,
DBAdaptorProductInput.KEY_MANUFACTURER,
DBAdaptorProductInput.KEY_VISC40,
DBAdaptorProductInput.KEY_VISC100,
DBAdaptorProductInput.KEY_VI,
DBAdaptorProductInput.KEY_DEN15C,
DBAdaptorProductInput.KEY_VISCTEXT,
DBAdaptorProductInput.KEY_BASEOILTYPE,
DBAdaptorProductInput.KEY_BASEOIL,
DBAdaptorProductInput.KEY_ADDITIVES,
DBAdaptorProductInput.KEY_OTHERADDITIVES,
DBAdaptorProductInput.KEY_THICKENER,
DBAdaptorProductInput.KEY_NLGI,
DBAdaptorProductInput.KEY_COMMENT,
DBAdaptorProductInput.KEY_PACKAGES,
DBAdaptorProductInput.KEY_AREA,
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.code,
R.id.name,
R.id.manufacturer,
R.id.visc40,
R.id.visc100,
R.id.viscindex,
R.id.den15c,
R.id.visctext,
R.id.baseoiltype,
R.id.baseoil,
R.id.additives,
R.id.otheradditives,
R.id.thickener,
R.id.nlgi,
R.id.comments,
R.id.packages,
R.id.area,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
dataAdapter = new SimpleCursorAdapter(
this, R.layout.activity_product_review_info, cursor, columns, to, 0);
ListView listView = (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
//SetOnItemClickListener for the ListView
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> listView, View view,
int position, long id) {
// Get the cursor, positioned to the corresponding row in the result set
Cursor cursor = (Cursor) listView.getItemAtPosition(position);
// Get the Customer Name from this row in the database.
String countryCode = cursor.getString(cursor.getColumnIndexOrThrow("ProductName"));
Toast.makeText(getApplicationContext(), countryCode, Toast.LENGTH_SHORT).show();
}
});
}
You need to have a custom adapter that extends BaseAdapter or SimpleCursorAdapter.
In the adapter's getView() method set the onClickListener for your ImageView.
I have a ListView that is fed by an SQLiteDB. On each row returned, I have a clickable TextView that onClick should delete the item on that row. So I need to find the sql rowid, so I can call deleteItem(rowid).
I've tried putting in an invisible TextView that I fill with the sql rowid as the ListView is populated, it works. But I set content view to R.layout.list_view and the invisible TextView is in R.layout.list_item (custom layout for each item line), so I can't seem to access it.
How do I go about making this work or is there a better way?
Here is the code that populates the listview:
private void fillData() {
// Get all of the notes from the database and create the item list
Cursor c = mDbHelper.fetchAllNotes();
startManagingCursor(c);
String[] from = new String[] { CommonDbAdapter.KEY_NOTES };
int[] to = new int[] { R.id.text1 };
// Now create an array adapter and set it to display using our row
SimpleCursorAdapter notes =
new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);
}
Here is my current click listener, I'm not sure how to differentiate between a click on the item, which returns the item to another activity and a click on the textview that would delete the item.
itemList = (ListView) findViewById(android.R.id.list);
itemList.setTextFilterEnabled(true);
itemList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> a, View v, int position, long id) {
Intent intent = new Intent();
Bundle b = new Bundle();
b.putString("TEXT", ((TextView)v.findViewById(R.id.text1)).getText().toString());
intent.putExtras(b);
setResult(SUCCESS_RETURN_CODE, intent);
finish();
}
});
I was originally trying to get the rowid and use a simple onClick set in the layout. But had problems getting the rowid.
public void clickDelete(View view) {
mDbHelper.deleteNote(rowid);
}
here is a quick way to get a click listener for just your textview:
replace your lines:
SimpleCursorAdapter notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);
with this:
setListAdapter(new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to) {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
final TextView t = (TextView)v.findViewById(R.id.text1);
t.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(v.getContext(), "Hello " + t.hashCode(), Toast.LENGTH_SHORT).show();
}
});
return v;
}
});
now, your text1 view will have an onclick listener, and you can do whatever you want. you need to store the rowId somewhere accessible from inside the onClick method though.
this doesn't exactly answer the question i guess, but it gives you a click listener for an individual view in the listview.
you really should implement a custom CursorAdapter class to do something like this, although you could hack around and retrieve the rowId from somewhere
or you could instead use an invisible textview and add an onclick listener to it(like i've shown above), grab it's value(which is a rowId), and perform an operation.
Are you using a CursorAdapter? If so you can query the Cursor directly for the rowid.
You may want to use OnItemClickListener instead of an OnClickListener. This will set you up with the ListView, the position and the id. I believe if you are using a CursorAdapter that the id given to you is the actual rowid of the row in the database.
Edit: if using OnItemClickListener is not possible, you'll have to change to CursorAdapter from SimpleCursorAdapter to do this. In your bindView method you'll have access to the rowid of the View you are creating, and you can reference this in the OnClickListener you create.
I have a List of Items which I retrieved from my Sqlite DB...
I want to set a Click event for each item. How I can customize this event based on the Item clicked????
Be descriptive... I am a beginner.
This is the method that I used to fill data in my List:
private void fillData() {
db = new DBAdapter(this);
db.open();
ArrayList db_results = new ArrayList();
//All Category
//Cursor cursor = db.getAllTitles();
//Single Category
Cursor cursor = db.getTitle(1);
if (cursor.moveToFirst())
{
do {
db_results.add(cursor.getString(4));
} while (cursor.moveToNext());
}
cursor.close();
this.list.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, db_results));
}
Call setOnItemClickListener() on the ListView. The AdapterView.OnItemClickListener listener you provide will be given the position (0-based index) and ID (if you were using a CursorAdapter, as you should be, rather than converting the Cursor into an ArrayList), so you will know which item was clicked upon.