I always cant delete first two sometimes three records. They are on Listview, when you press element you will see delete button on another layout. On Log im getting correct index for every element.
So here is my code:
Main Activity:
viewOfT.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent i=new Intent(MainActivity.this, popupWindow.class);
i.putExtra("index",id);
startActivity(i);
}
});
}
public void populateListView() {
Cursor data = db.getData();
ArrayList<String> listData = new ArrayList<>();
while(data.moveToNext()){
k.setId(data.getInt(0));
k.setTask(data.getString(1));
listData.add("- " + k.getTask());
}
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_list_item_1,
listData);
viewOfT.setAdapter(arrayAdapter);
arrayAdapter.notifyDataSetChanged();
viewOfT.invalidateViews();
Delete button in other activity:
del.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Bundle bundle=getIntent().getExtras();
long value=bundle.getLong("index");
db.deleteRecord(value);
finish(); }
});
And SQLHelper:
public void deleteRecord(long id) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, KEY_ID + "=" + id, null);
close();
}
1) Delete populateListView method
2) Add the following as class variables:-
SimpleCursorAdpater sca;
Cursor data;
3) in the onCreate method add :-
data = getData();
sca = new SimpleCursorAdapter(
this, // Context same as for array adapter
android.R.layout.simple_list_item_1, // layout to be used
data, // <<<<<<<< the cursor to be used for the list
new String[]{"columnname_to_be_displayed"}, // <<<<<<<< cursor column to display name
new int[android.R.id.text1], // the view into which the cursor data will be placed
0 // a flag 0 is fine
);
viewOfT.setAdapter(arrayAdapter);
4) Add a new method to override the 'onResume' method (or alter it if already overridden) :-
#Override
protected void onResume() {
super.onResume();
data = getData();
sca.swapCursor(); // can you sca.notifyDatasetChanged()
}
As you are calling another activity to delete the task, onResume will be called when returning from the other activity so the data is again retrieved from the database (deleted row will not exist) and the adpater is told to refresh the data.
You should ideally also override the onDestroy() method to close the cursor (data.close();)
Important Consideration
A cursor column named _id must exist for CursorAdapters (that's how the SimpleCursorAdapter knows what pass to the onItemClickListener).
if KEY_ID does not equate to _id; you either need to change KEY_ID to _id or amend the getData() method to include the _id column (which should be the value of the row's identifier) e.g. assuming a very basic query:
public Cursor getData() {
return db.query(TABLE_NAME,"rowid AS _id, *",null,null,null,null,null);
} // Note! will add an extra column so beware if using column offsets
or perhaps :-
public Cursor getData() {
return db.query(TABLE_NAME,KEY_ID + " AS _id, *",null,null,null,null,null);
} // Note! will add an extra column so beware if using column offsets
A Note on Column offsets
In your code you have :-
k.setId(data.getInt(0));
k.setTask(data.getString(1));
0 and 1 are column offsets (and could change e.g. the two alternative getData() methods). As such it's generally better to take advantage of the Cursor method getColumnIndex(columnname) e.g. the above could be :-
k.setId(data.getInt(data.getColumnIndex(KEY_ID));
k.setTask(data.getString(data.getColumnIndex("TASK_COLUMN")));
Note! not that you will need to create an Array as the SimpleCursorAdpater takes the cursor as the source. (KEY_ID would likely have to be prefixed with the DatabaseHelper Class).
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I am opening a new activity which uses CursorLoader to get data from local SQLite db. Whenever I click the listitem, for some reason it always populates the values from the first item. I want to populate the values for the specific list item I clicked. For eg: If I click "watch" item, it still populates "book" values in Edittext. Am I missing anything here?
Here is my code for CursorLoader:
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
String[] projection = {
ItemContract.ItemEntry._ID,
ItemContract.ItemEntry.COLUMN_ITEM_NAME,
ItemContract.ItemEntry.COLUMN_ITEM_QUANTITY,
ItemContract.ItemEntry.COLUMN_ITEM_PRICE,
ItemContract.ItemEntry.COLUMN_ITEM_IMAGE
};
return new CursorLoader(this, ItemContract.ItemEntry.CONTENT_URI,projection,null,null,null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
if (cursor == null || cursor.getCount() < 1) {
return;
}
if (cursor.moveToFirst()) {
int nameColumnIndex = cursor.getColumnIndex(ItemContract.ItemEntry.COLUMN_ITEM_NAME);
int quantityColumnIndex = cursor.getColumnIndex(ItemContract.ItemEntry.COLUMN_ITEM_QUANTITY);
int priceColumnIndex = cursor.getColumnIndex(ItemContract.ItemEntry.COLUMN_ITEM_PRICE);
int imageColumnIndex = cursor.getColumnIndex(ItemContract.ItemEntry.COLUMN_ITEM_IMAGE);
String editCurrentName = cursor.getString(nameColumnIndex);
int editCurrentQuantity = cursor.getInt(quantityColumnIndex);
Float editCurrentPrice = cursor.getFloat(priceColumnIndex);
String editCurrentImage = cursor.getString(imageColumnIndex);
if(editCurrentImage != null) {
editImage.setVisibility(View.VISIBLE);
editImage.setImageURI(Uri.parse(editCurrentImage));
}
else {
editImage.setVisibility(View.GONE);
}
editName.setText(editCurrentName);
editQuantity.setText(Integer.toString(editCurrentQuantity));
editPrice.setText(Float.toString(editCurrentPrice));
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
Log.e("EDITACTIVITY", "onLoaderReset: ");
editName.setText("");
editQuantity.setText("");
editPrice.setText("");
editImage.setImageDrawable(null);
}
This will be an issue with how you retrieve the Cursorfrom the ListView or AnyView's position. The way to retrieve values from the Cursor you got from the onItemClickListener in the ListView or AnyView's itself:
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);
// Use the Cursor to retrieve the value from here!
}
You are simple loading cursor, so without passing condition it will return all data and then also you are fetching first row data. So it will only return very first data in all scenarios.
Solution
In this case there are three solutions available which you can use.
Solution1:
When user click on item, at that time you can fetch the item object and pass the values to edit activity.
Something like this: [http://www.viralandroid.com/2016/04/start-new-activity-from-android-listview-onitem-clicked.html][1]
Solution2:
When user click on item, at that time fetch only the item id and pass to the edit activity. Now you have to pass argument as below in cursor loader.
// Here I am storing passed id in one variable, you have to set selected_item_id in intent while starting new activity
int selectedId = getIntent().getExtras().getInt("selected_item_id",0);
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
String[] projection = {
ItemContract.ItemEntry._ID,
ItemContract.ItemEntry.COLUMN_ITEM_NAME,
ItemContract.ItemEntry.COLUMN_ITEM_QUANTITY,
ItemContract.ItemEntry.COLUMN_ITEM_PRICE,
ItemContract.ItemEntry.COLUMN_ITEM_IMAGE
};
String selection = ItemContract.ItemEntry._ID + "=?";
String[] selectionArgs = { String.valueOf(selectedId) };
return new CursorLoader(this, ItemContract.ItemEntry.CONTENT_URI,projection, selection ,selectionArgs ,null);
}
Now, you will get actual result.
In third solution you have to use your own method for loader and then in finished you have to fetch one by one cursor data and then match with selectedId.
Last one is little bit complex and lengthy so try to use first or second only.
I need to delete an item permanently from ListView and then from database. I have a DatabaseHandler.java class, which has the delete function as:
// Deleting single contact, in DatabaseHandler.java class
public void deleteContact(Contact contact) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_CONTACTS, KEY_ID + " = ?",
new String[] { String.valueOf(contact.getID()) });
db.close();
}
Then I have a FriendList.java class, when the user's friends are displayed as an item in ListView. When I long press on an item, then I get the option of "Delete" and "Cancel" in Dialog Box. Now, when I click on delete, the item is deleted from the ListView, but, not from the database. How can I delete it from database as well?
The code for getting the option of "Delete" and "Cancel"
listview.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int position, long id) {
// TODO Auto-generated method stub
Intent i = new Intent(FriendList.this, Delete_Confirm.class).addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
//I am sending position of listitem in putExtra below//
i.putExtra("position", position);
startActivityForResult(i,CONFIRM);
item2 = (String) arg0.getItemAtPosition(position);
//Toast.makeText(FriendList.this, "Clicked"+item2, Toast.LENGTH_SHORT).show();
int l = item2.length();
c=0;
for(int j=0; j<=l; j++){
if(item2.charAt(j) != '9' || item2.charAt(j+1) != '1'){
c++;
}
else {
//Do nothing
break;
}
num = item2.substring(c, l);
}
Toast.makeText(FriendList.this, "Clicked: "+num, Toast.LENGTH_SHORT).show();
return true;
}
});
The corresponding code for onActivityResult is as follows:
#Override
public void onActivityResult(int reqCode, int resultCode, Intent data) {
super.onActivityResult(reqCode, resultCode, data);
switch (reqCode) {
case (CONFIRM) :
if(resultCode==RESULT_OK){
int posi = data.getIntExtra("position",0);
Log.d("msg","position is " + posi);
Log.d("msg","Do we reach here?");
final StableArrayAdapter adapter = new StableArrayAdapter(this,
android.R.layout.simple_list_item_1, list);
//db.deleteContact(posi);
list.remove(posi);
listview.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
break;
}}
Please suggest how can I delete it from database as well. Any help would be highly appreciated.
EDIT:
On uncommenting db.deleteContact(posi), I get the following error:
The method deleteContact(Contact) in the type DatabaseHandler is not applicable for the arguments (int)
Note that the function deleteContact has contact variable of the type Contact.
Its a compilation error.
You need to pass a Contact object to the method, not an integer.
When you delete.... Try Deleting first from database then from ListView..
example:
db.deleteContact(list.get(posi)); // this will get string
list.remove(posi);
DatabaseHandler class.......
public void deleteContact(String name){
Log.d("Name:",""+ name);
db.delete(TABLE_CONTACTS, KEY_NAME + " = ?", new String[] { name });
}
You can delete from database first then from ListView. And suggest Iterator to remove list element.
I think the problem is that position is not the corresponding id in the database. A possible solution would be to add a tag with the database id of the contact you have in this listitem. And when you remove it you get the tag with the id and delete the item from the database.
Edit (added clarification):
I would add in your listviewadapter something like:
yourcontactview.setTag(contact.getId());
in which you add to your view a tag with the database id of the corresponding contact.
Then where you delete the contact I would get the contact you want to delete with something like this:
Contact deletecontact = db.getContact(view.getTag());
db.deleteContact(deletecontact);
Of course you could change your
deleteContact(Contact contact) to a method in which you give the id instead of the contactobject.
This should hopefully work.
I've a list view which is populated by my database. Now in the OnItemClickListener I passed the row id to the next Activity. In that activity I have two text views and I want to add texts in those text views from the my database.
As a beginner I'm stuck here, What should I do now?
If the id(not the position of the item in the listviw) you are passing to the next activity is primary key or it is mapped somehow to your database table then you can simply query your database with a where clause to get the specific row from the table.
Another simple solution may be passing the data from the same activity to the another activity over the intent (if they are some small size), instead of making another query to the database tables.
Just pass in the row id to the database:
SqliteDatabase mySqlLiteDatabase;
View parentThis = (LinearLayout)inflater.inflate(R.layout.list_view);
lvDatabase = (ListView)parentThis.findViewById(R.id.listview);
lvDatabase.setAdapter(String[] list_Of_Items_From_Database);
lvDatabase.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
sql = "Select text from my_database where _id=" + id;
mySqlLiteDatabase.openDatabase(yourDatabasePath,null,SQLiteDatabase.OPEN_READWRITE);
Cursor c = mySqlLiteDatabase.rawquery(sql);
TextView textView = (TextView)parentThis.findViewById(R.id.mytextview);
if (c !=null) {
if (c.moveToFirst()) {
textView.setText(c.getString(c.getColumnIndex("Text")));
}
}
}
});
Hopefully your database table has an identity column in it (_id)
pass all the data in an array by quering into db and then display it in listView.
public ArrayList<String> getAllNumbers(){
ArrayList<String> labels = new ArrayList<String>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_CONTACTS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
if (cursor.moveToFirst()) {
do {
String number=cursor.getString(1);
labels.add(number);
} while (cursor.moveToNext());
}
// closing connection
cursor.close();
db.close();
// returning lables
return labels;
}
then fetch it on item click of listview and pass it to another activity.
#Override
public boolean onItemLongClick(AdapterView<?> parent,
final View view, final int position, long arg3) {
title = view.getTag(R.string.title).toString();
Intent intent_compose = new Intent(ActivityA.this,
ActivityB.class);
startActivity(intent_compose);
}
I'm looking to add a new feature to my BETA version of my application.I think I need help on my approach to handling deleting a specific row.
I've been able to do everything I want with the databases in my app except for deleting a particular row or ID value from both database tables.
I'm calling a deleteClient() and passing the cursor in my DBAdapter. This table takes a long value for the rowID.
DBAdapter:
public boolean deleteClient(long rowId)
{
return db.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}
DatabaseHandler creates a second database for other storage work but should delete the same:
public boolean delete(long rowId)
{
return db.delete(TABLE_LABELS, KEY_ID + "=" + rowId, null) > 0;
}
In my class I've tried a few variations on like this:
//db = the databaseadapter
db.open();
long loadID = contactList.getSelectedItemId();
//contact list is a spinner that is auto populated with each new entry added to it.
Cursor cursor = db.getClient(loadID);
db.deleteClient(cursor);
db.close();
AND THIS
dh.getWritableDatabase();
long currentlySelected = contactList.getSelectedItemId();
dh.delete(currentlySelected);
dh.close();
One deletes but not the right selection - the other causes an immediate crash. DDMS has given hints but I cant figure out what else could be going on.
Any thoughts on this structure in general or better techniques on this approach?
Spinner loaded like this:
private void loadSpinnerData() {
// database handler
DatabaseHandler dbh = new DatabaseHandler(getApplicationContext());
// Spinner Drop down elements
List<String> lables = dbh.getAllLabels();
// Creating adapter for spinner
ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_spinner_item, lables);
// Drop down layout style - list view with radio button
dataAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
// attaching data adapter to spinner
contactList.setAdapter(dataAdapter);
}
I am trying to add image button to my custom SimpleCursorAdapter for my ListView in my project but I have got one problem with repeating and totally random value of one field.
This is a code of it:
public class MyCursorAdapter extends SimpleCursorAdapter {
public MyCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
super.bindView(view, context, cursor);
final Context t = context;
final Cursor c = cursor;
ImageButton delimageButton = (ImageButton)view.findViewById(R.id.deletebutton);
delimageButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Toast.makeText(t,
"Delete ID: " + c.getInt(c.getColumnIndex(MyDBAdapter.KEY_ID)), Toast.LENGTH_SHORT).show();
}
});
if(cursor.getLong(cursor.getColumnIndex(MyDBAdapter.KEY_OWNID))>0)
{
TextView own = (TextView)view.findViewById(R.id.ownInfo);
own.setText("OWN");
}
else
{
TextView own = (TextView)view.findViewById(R.id.ownInfo);
own.setText("");
}
}
}
Now, when I press delimageButton what I get is some random ID of one record (row) of ListView that is in current view (I can see it, but it is not the correct id) e.g. if you can see like 5 rows on screen and you press on one of buttons you will get id of other row (one of those 5) but not this one which you pressed (in most of the cases). I remember that there was some trick with this own TextView, but I don't see how it can be putted in here.
So, can you please advice me how can I make it to show correct ID?
I'll be glad for help.
EDIT
There is a whole code responsible for setting a ListView together with calling MyCursorAdapter:
private void refreshList() {
mySQLiteAdapter = new MyDBAdapter(this);
mySQLiteAdapter.open();
String[] columns = { MyDBAdapter.KEY_TITLE, MyDBAdapter.KEY_GENRE,
MyDBAdapter.KEY_OWNID, MyDBAdapter.KEY_ID };
Cursor contentRead = mySQLiteAdapter.getAllEntries(false, columns,
null, null, null, null, MyDBAdapter.KEY_TITLE, null);
startManagingCursor(contentRead);
Log.d(TAG, Integer.toString(contentRead.getCount()));
MyCursorAdapter adapterCursor = new MyCursorAdapter(this,
R.layout.my_row, contentRead, columns, new int[] {
R.id.rowTitle, R.id.detail });
this.setListAdapter(adapterCursor);
mySQLiteAdapter.close();
}
To clarify, the activity is ListActivity.
Your OnClickListener is getting the id from the cursor when it is clicked, not when it is constructed. Meanwhile, the listview is changing the cursor position as you scroll around.
I think if you look carefully, you'll find the Toast is displaying the id of the last item that was loaded into view rather than the item that contains the button you clicked.
You can solve this by getting the id when you construct the click listener, like this:
delimageButton.setOnClickListener(new OnClickListener() {
private int id = c.getInt(c.getColumnIndex(MyDBAdapter.KEY_ID));
#Override
public void onClick(View arg0) {
Toast.makeText(t,
"Delete ID: " + id, Toast.LENGTH_SHORT).show();
}
});