My Activity Code
Please help me how to delete item in list view that connect to database in Android Studio. This my code :
mainListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView parent, View view, final int position, final long id) {
final AlertDialog.Builder b = new AlertDialog.Builder(UserList.this);
b.setIcon(android.R.drawable.ic_dialog_alert);
b.setMessage("Ingin menghapus data?");
b.setPositiveButton("Ya",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
IDTable = IDList.get(position);
userList.remove(position);
UserList.this.listAdapter.notifyDataSetChanged();
InfoPokok info = new InfoPokok();
info.setId(IDTable);
System.out.println("ID : " + info.getId());
infoPokokDao.deleteInfoPokok(info);
}
});
b.setNegativeButton("Tidak",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.cancel();
}
});
b.show();
return true;
}
});
DAO :
public void deleteInfoPokok(InfoPokok infoPokok) {
String id = infoPokok.getId() + "";
long deleteId = database.delete(MySQLiteHelper.TABLE_INFO_POKOK, MySQLiteHelper.COLUMN_ID
+ " =?", new String[]{id});
Cursor cursor = database.query(MySQLiteHelper.TABLE_INFO_POKOK,
allColumns, MySQLiteHelper.COLUMN_ID + " = " + deleteId, null,
null, null, null);
cursor.moveToFirst();
cursor.close();
}
IN YOUR DISPLAYACTIVITY.JAVA
btnDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DataBaseHandler db = new DataBaseHandler(DisplayImageActivity.this);
Log.d("Delete Image: ", "Deleting.....");
db.deleteCloth(new Cloth(imageId));
Intent i = new Intent(DisplayImageActivity.this, MainActivity.class);
startActivity(i);
finish();
}
});
AND THEN IN DATABASEHANDLER.JAVA
public void deleteCloth(Cloth cloth) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_CLOTHES, KEY_ID + " = ?", new String[] { String.valueOf(cloth.getID()) });
db.close();
}
I think the best way to achieve this is to write a delete method in your Provider :
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
//the provided is requested to delete data - so we'll delete it in the db:
SQLiteDatabase db = dbHelper.getWritableDatabase();
int result = db.delete(getTableName(uri), selection, selectionArgs);
// notify the change
getContext().getContentResolver().notifyChange(uri, null);
//return the number of rows deleted
//it's what we got from the db.delete
return result;
}
and then just call it like :
getContentResolver().delete(YOUR_CONTENT_URI, String where, String[] selectionArgs);
Do u use CursorAdapter or ArrayAdapter?
CursorAdapter - 1. Use AsyncTask or something that u build that delete the data on back thread and not on the UI (currently onLongClick is being called on the UI and you are accessing DB on the UI, bad practice). 2. When the delete is done you can restart your loader to requery the DB and the cursor wil update. Think about maybe showing a progress bar if u will have a large DB or adding calls to server.
ArrayAdapter - Based on array adpter that is a place holder for the cursor. 1. Delete the data from the array and notifyDataSetCahnged, UI thread.
2. Delete the item from DB on back thread.
This way the user wont feel any Glitch.
Good luck.
Related
This question has been asked before but none of the implementations helped me so far.
I'm building a to do app and I'm displaying my items in a listview, using SQLite for persistence. I'm able to dynamically add items to my listview and successfully store them in my database, but I'm not able to delete them from the screen or the table. I know the reason why. My SQLite Row ID does not match my ListView. But the other problem is that I should still be able to delete items off my screen and my table with positions that does match the SQLite Row ID (For example, my 3rd To Do in the list) but I'm not able to delete anything.
This is my method that is supposed to delete items from the database:
public boolean itemDeleteFromDatabase(long id) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
boolean databaseDelete = database.delete(TABLE_NAME, TO_DO + "=?" + id, null) > 0;
listItems.setAdapter(adapter);
return databaseDelete;
}
And I'm calling this method from my OnItemLongClick method, passing in the ListView position as the parameter:
listItems.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapter, View item, int position, long id) {
toDoItems.remove(position);
itemDeleteFromDatabase(id);
MainActivity.this.adapter.notifyDataSetChanged();
return true;
}
});
This is the stacktrace. The problem with this is that it only addresses 1 problem in the code:
FATAL EXCEPTION: main
Process: ca.ozbek.preworktodoapp, PID: 2105
android.database.sqlite.SQLiteException: variable number must be between ?1 and ?999 (code 1): , while compiling: DELETE FROM student WHERE todo=?0
Adding Source Code per request
MainActivity.java
public class MainActivity extends AppCompatActivity {
DatabaseHelper databaseHelper;
private final int REQUEST_CODE = 10;
ArrayList <String> toDoItems = new ArrayList<>();
ArrayAdapter<String> adapter;
ListView listItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listItems = (ListView) findViewById(R.id.listViewItems);
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, toDoItems);
listItems.setAdapter(adapter);
databaseHelper = new DatabaseHelper(this);
getToDos();
listItems.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapter, View item, int position, long id) {
toDoItems.remove(position);
itemDeleteFromDatabase(id + 1);
MainActivity.this.adapter.notifyDataSetChanged();
return true;
}
});
listItems.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View item, int pos, long id) {
Intent intent = new Intent(MainActivity.this, EditItemActivity.class);
intent.putExtra("item", toDoItems.get(pos));
intent.putExtra("itemPos", String.valueOf(pos));
startActivityForResult(intent, REQUEST_CODE);
}
});
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE) {
String item = data.getStringExtra("item");
int itemPosition = Integer.parseInt(data.getStringExtra("itemPos"));
toDoItems.add(itemPosition, item);
toDoItems.remove(itemPosition + 1);
adapter.notifyDataSetChanged();
}
}
public void addItem(View v) {
EditText newItem = (EditText) findViewById(R.id.itemInputEditText);
if (newItem.getText().length() == 0) {
Toast.makeText(this, "You need to enter a to do.", Toast.LENGTH_SHORT).show();
} else {
String item = newItem.getText().toString();
databaseHelper.insertData(item);
adapter.add(item);
newItem.setText("");
}
}
public void getToDos(){
SQLiteDatabase database = databaseHelper.getWritableDatabase();
Cursor cursor = database.rawQuery("select * from student",null);
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
String name = cursor.getString(cursor.getColumnIndex("todo"));
adapter.add(name);
adapter.notifyDataSetChanged();
cursor.moveToNext();
}
}
}
public boolean itemDeleteFromDatabase(Long id) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
boolean databaseDelete = database.delete(TABLE_NAME, TO_DO + "=?", new String[]{Long.toString(id)}) > 0;
listItems.setAdapter(adapter);
return databaseDelete;
}
}
DatabaseHelper.java
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "todo.db";
public static final String TABLE_NAME = "student";
public static final String ID = "id";
public static final String TO_DO = "todo";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String CREATE_TO_DO_TABLE = "CREATE TABLE "
+ TABLE_NAME
+ "("
+ ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ TO_DO
+ " TEXT"
+ ")";
sqLiteDatabase.execSQL(CREATE_TO_DO_TABLE);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(sqLiteDatabase);
}
public boolean insertData(String todo) {
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(TO_DO, todo);
long result = sqLiteDatabase.insert(TABLE_NAME, null, contentValues);
if (result == -1) {
return false;
} else {
return true;
}
}
public Cursor getListContents() {
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
Cursor data = sqLiteDatabase.rawQuery("SELECT * FROM " + TABLE_NAME, null);
return data;
}
}
SQL is basically saying that you haven't provided an argument to match the placement ?. i.e.
boolean databaseDelete = database.delete(TABLE_NAME, TO_DO + "=?" + id, null) > 0;
Is effectively saying DELETE FROM table WHERE TO_DO =unobtainablevale 10
10 being a made-up id for demonstration
You could change it to
boolean databaseDelete = database.delete(TABLE_NAME, TO_DO + "=" + id, null) > 0;
or to
boolean databaseDelete = database.delete(TABLE_NAME, TO_DO + "=?", new String[]{Long.toString(id)}) > 0;
The latter probably being considered the better.
P.S. not tested so the odd typo might exist.
Solution 1 using a SimpleCursorAdapter as opposed to an ArrayAdpater
1) in DatabaseHelper change public static final String ID = "id"; to be public static final String ID = "_id"; (i.e add the underscore, suggest do this irrespective of method used but NEEDED for CursorAdapter)
Note! This will require the existing database to be deleted. Use Settings/Apps, select App and then clear data or uninstall app.
2) add the lines indicated with <<<<< to MainActivity (preparing to use Cursor Adapter, ps will leave the ArrayAdapter stuff generally asis but have to remove some)
ArrayList<String> toDoItems = new ArrayList<>();
ArrayAdapter<String> adapter;
SimpleCursorAdapter altadapter; //<<<<<<<<<
Cursor itemlistcursor; //<<<<<<<<<
ListView listItems;
3) Add override for onDestroy method (not required but cleans up cursor) :-
#Override
public void onDestroy() {
super.onDestroy();
itemlistcursor.close();
}
4) Add altertantive method e.g. getItemListAsCursor to get data:-
public void getItemListAsCursor() {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
itemlistcursor = database.query(TABLE_NAME,null,null,null,null,null,null);
}
Note! uses query method instead of rawQuery but equates to SELECT * FROM student;
5) Change itemDeleteFromDatabase to use ID column not the TODO column (didn't spot this before) and comment out lines as per the code below:-
public boolean itemDeleteFromDatabase(Long id) {
SQLiteDatabase database = databaseHelper.getWritableDatabase();
boolean databaseDelete = database.delete(TABLE_NAME, ID + "=?", new String[]{Long.toString(id)}) > 0;
//listItems.setAdapter(adapter);
return databaseDelete;
}
6) Comment out the lines as below (get rid of using ArrayAdapater) :-
listItems = (ListView) findViewById(R.id.listViewItems);
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, toDoItems);
//listItems.setAdapter(adapter);
databaseHelper = new DatabaseHelper(this);
//getToDos();
7) Change onItemLongClickListener as below
listItems.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapter, View item, int position, long id) {
//toDoItems.remove(position);
itemDeleteFromDatabase(id); //<<<<<<
getItemListAsCursor(); //<<<<<<
//MainActivity.this.adapter.notifyDataSetChanged();
altadapter.swapCursor(itemlistcursor); //<<<<<<
return true;
}
});
Note! could keep notifyDatasetChanged (I just prefer swapCursor);
8) Finally add the following just after the commented out //getToDos line :-
getItemListAsCursor();
altadapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1,
itemlistcursor,
new String[]{ TO_DO},
new int[]{android.R.id.text1},
0);
listItems.setAdapter(altadapter);
Solution 2 using ArrayAdpater
1) Add the complimentary Array for the ID (as per the //<<<<<< line):-
ArrayList <String> toDoItems = new ArrayList<>();
ArrayList<Long> toDoItemsID = new ArrayList<>(); //<<<<<<
ArrayAdapter<String> adapter;
ListView listItems;
2) Change insertData method in DatabaseHelper to return the id by replacing the method with :-
public long insertData(String todo) {
SQLiteDatabase sqLiteDatabase = this.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(TO_DO, todo);
return sqLiteDatabase.insert(TABLE_NAME, null, contentValues);
}
3) Change getToDos method to store id into the compliementary array (//<<<<< ):-
public void getToDos(){
SQLiteDatabase database = databaseHelper.getWritableDatabase();
Cursor cursor = database.rawQuery("select * from student",null);
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
String name = cursor.getString(cursor.getColumnIndex(TO_DO));
adapter.add(name);
toDoItemsID.add(cursor.getLong(cursor.getColumnIndex(ID))); //<<<<<<
adapter.notifyDataSetChanged();
cursor.moveToNext();
}
}
}
Note! I have also replaced "todo" with TO_DO
4) Change addItem method to also store id
public void addItem(View v) {
EditText newItem = (EditText) findViewById(R.id.itemInputEditText);
if (newItem.getText().length() == 0) {
Toast.makeText(this, "You need to enter a to do.", Toast.LENGTH_SHORT).show();
} else {
String item = newItem.getText().toString();
//databaseHelper.insertData(item); //OLD
toDoItemsID.add(databaseHelper.insertData(item)); //<<<<<<<
adapter.add(item);
newItem.setText("");
}
}
Note! I don't like this at all I can envisage issue with keeping toDoItemsID in sync, plus this does currently cater for a not inserted (easy to do as return from insertData should be > 0).
5) Finally the onItemLongClickListener changes :-
listItems.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapter, View item, int position, long id) {
itemDeleteFromDatabase(toDoItemsID.get(position)); //<<<<<<
toDoItems.remove(position);
toDoItemsID.remove(position); //<<<<<<
//itemDeleteFromDatabase(id + 1); // REMOVE
MainActivity.this.adapter.notifyDataSetChanged();
return true;
}
});
I've tested the above, but may have inadvertently missed something when copying.
Is there a way to delete a row of data in SQLite with RecyclerView? Before when I used a ListView I just set and onClickListener and did :
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id)
Then passed the id onto my database like so: databaseAdapter.deleteScore(id)
but now since it is all handled in the RecyclerViewAdapter class can you still get the row id and delete it?
Figured it out. What I did was in the RecyclerView's onLongClick(final View view) I created an instance of my sql database and called my deleteScore method as so: sqLiteDBadapter.deleteScore(temp2); <- temp2 is the rowid of the list item in the sql database.
And here is my getRowid and my deleteScore methods in my SQLiteDBadapter class:
getRowid:
public String getRowid(String date) {
mDbHelper = new DatabaseHelper(context);
db = mDbHelper.getReadableDatabase();
Cursor c = db.rawQuery("SELECT * from " + DATABASE_TABLE + " WHERE date = ?" , new String[] { date });
if (c.moveToFirst()){
long temp;
temp = c.getLong(c.getColumnIndex(KEY_ROWID));
rowID = String.valueOf(temp);
Log.i("----_ROW ID = ", rowID);
}else if (!c.moveToFirst())
Log.i("CURSOR ERROR", " CURSOR INDEX MOST LIKELY 0");
else
c.moveToFirst();
return rowID;
}
deleteScore:
public boolean deleteScore(long rowId) {
return db.delete(DATABASE_TABLE,KEY_ROWID + "= ?", new String[] { rowID}) > 0;
}
i want to search in database in my android application. when i get a select query if its been or not been in database its show nothing.
this is my code:
final String havy = edtSearch.getText().toString();
btnSearch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Cursor cursor = G.dataBase.rawQuery("SELECT * FROM db WHERE info_title=" + "'" + havy + "'", null);
if (cursor.moveToNext()) {
Intent intent = new Intent(SearchActivity.this, DetailActivity.class);
intent.putExtra(G.selectedItem.face, true);
SearchActivity.this.finish();
} else {
Toast.makeText(SearchActivity.this, "shows something", Toast.LENGTH_SHORT).show();
}
}
});
Check if your cursor is not null and size is greater that zero, then iterate over the cursor.
I am using a SQLite database and a ContentProvider to fill a ListFragment. The problem is that ListFragment is not getting refreshed after I add a item. The ListFragment is empty. I have to close and reopen the app to show the added item in the list.
I try to update it like this:
public class RoomListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
//adapter using SQLite and ContentProvider to fill ListFragment
private SimpleCursorAdapter dataAdapter;
//needed for create room dialog
private EditText enter_room;
private static View textEntryView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//display ActionBar items
setHasOptionsMenu(true);
// TODO: replace with a real list adapter.
displayListView();
}
#Override
public void onResume() {
super.onResume();
//Starts a new or restarts an existing Loader in this manager
getLoaderManager().restartLoader(0, null, this);
}
#Override
public void onDestroy() {
super.onDestroy();
}
private void displayListView() {
// The desired columns to be bound
String[] columns = new String[] {
Database.KEY_GROUPADDRESS,
Database.KEY_NAME,
Database.KEY_DPT
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.groupaddress,
R.id.name,
R.id.dpt,
};
// create an adapter from the SimpleCursorAdapter
dataAdapter = new SimpleCursorAdapter(
getActivity(),
R.layout.device_info,
null,
columns,
to,
0);
//set SimpleCursorAdapter to ListFragmentAdapter
setListAdapter(dataAdapter);
//Ensures a loader is initialized and active.
getLoaderManager().initLoader(0, null, this);
}
// This is called when a new Loader needs to be created.
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = {
Database.KEY_ROWID,
Database.KEY_GROUPADDRESS,
Database.KEY_NAME,
Database.KEY_DPT};
CursorLoader cursorLoader = new CursorLoader(getActivity(),
MyContentProvider.CONTENT_URI, projection, null, null, null);
return cursorLoader;
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
dataAdapter.swapCursor(data);
dataAdapter.notifyDataSetChanged();
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
dataAdapter.swapCursor(null);
}
I add a item with this code:
//Handle OnClick events on ActionBar items
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// handle item selection
switch (item.getItemId()) {
case R.id.menu_add:
//Toast.makeText(getActivity(), "Click", Toast.LENGTH_SHORT).show();
LayoutInflater factory = LayoutInflater.from(getActivity());
//textEntryView is an Layout XML file containing text field to display in alert dialog
textEntryView = factory.inflate(R.layout.dialog_add_room, null);
//get the control from the layout
enter_room = (EditText) textEntryView.findViewById(R.id.enter_room);
//create Dialog
final AlertDialog.Builder alert1 = new AlertDialog.Builder(getActivity());
//configure dialog
alert1.setTitle("Raum hinzufügen:").setView(textEntryView)
.setPositiveButton("Hinzufügen",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
String roomname = enter_room.getText().toString();
Log.d("Insert: ", "Inserting ..");
ContentValues values = new ContentValues();
//TODO Richtige Spalte für Raumname verwenden
values.put(Database.KEY_NAME, roomname);
getActivity().getContentResolver().insert(MyContentProvider.CONTENT_URI, values);
dataAdapter.notifyDataSetChanged();
}
}).setNegativeButton("Abbrechen",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
//cancel dialog
}
});
alert1.show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
My ContentProvider:
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
public class MyContentProvider extends ContentProvider{
private MyDatabaseHelper dbHelper;
private static final int ALL_COUNTRIES = 1;
private static final int SINGLE_COUNTRY = 2;
// authority is the symbolic name of your provider
// To avoid conflicts with other providers, you should use
// Internet domain ownership (in reverse) as the basis of your provider authority.
private static final String AUTHORITY = "de.mokkapps.fixknxdemo.contentprovider";
// create content URIs from the authority by appending path to database table
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY + "/countries");
// a content URI pattern matches content URIs using wildcard characters:
// *: Matches a string of any valid characters of any length.
// #: Matches a string of numeric characters of any length.
private static final UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "countries", ALL_COUNTRIES);
uriMatcher.addURI(AUTHORITY, "countries/#", SINGLE_COUNTRY);
}
// system calls onCreate() when it starts up the provider.
#Override
public boolean onCreate() {
// get access to the database helper
dbHelper = new MyDatabaseHelper(getContext());
return false;
}
//Return the MIME type corresponding to a content URI
#Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case ALL_COUNTRIES:
return "vnd.android.cursor.dir/vnd.com.as400samplecode.contentprovider.countries";
case SINGLE_COUNTRY:
return "vnd.android.cursor.item/vnd.com.as400samplecode.contentprovider.countries";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
// The insert() method adds a new row to the appropriate table, using the values
// in the ContentValues argument. If a column name is not in the ContentValues argument,
// you may want to provide a default value for it either in your provider code or in
// your database schema.
#Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case ALL_COUNTRIES:
//do nothing
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
long id = db.insert(Database.SQLITE_TABLE, null, values);
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(CONTENT_URI + "/" + id);
}
// The query() method must return a Cursor object, or if it fails,
// throw an Exception. If you are using an SQLite database as your data storage,
// you can simply return the Cursor returned by one of the query() methods of the
// SQLiteDatabase class. If the query does not match any rows, you should return a
// Cursor instance whose getCount() method returns 0. You should return null only
// if an internal error occurred during the query process.
#Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(Database.SQLITE_TABLE);
switch (uriMatcher.match(uri)) {
case ALL_COUNTRIES:
//do nothing
break;
case SINGLE_COUNTRY:
String id = uri.getPathSegments().get(1);
queryBuilder.appendWhere(Database.KEY_ROWID + "=" + id);
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
Cursor cursor = queryBuilder.query(db, projection, selection,
selectionArgs, null, null, sortOrder);
return cursor;
}
// The delete() method deletes rows based on the selection or if an id is
// provided then it deleted a single row. The methods returns the numbers
// of records delete from the database. If you choose not to delete the data
// physically then just update a flag here.
#Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case ALL_COUNTRIES:
//do nothing
break;
case SINGLE_COUNTRY:
String id = uri.getPathSegments().get(1);
selection = Database.KEY_ROWID + "=" + id
+ (!TextUtils.isEmpty(selection) ?
" AND (" + selection + ')' : "");
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
int deleteCount = db.delete(Database.SQLITE_TABLE, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return deleteCount;
}
// The update method() is same as delete() which updates multiple rows
// based on the selection or a single row if the row id is provided. The
// update method returns the number of updated rows.
#Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case ALL_COUNTRIES:
//do nothing
break;
case SINGLE_COUNTRY:
String id = uri.getPathSegments().get(1);
selection = Database.KEY_ROWID + "=" + id
+ (!TextUtils.isEmpty(selection) ?
" AND (" + selection + ')' : "");
break;
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
int updateCount = db.update(Database.SQLITE_TABLE, values, selection, selectionArgs);
getContext().getContentResolver().notifyChange(uri, null);
return updateCount;
}
}
You should call notifyDataSetChanged(); from within your content providers' insert method and supply the URI as an argument.
At the point in time you are currently calling the notifyDataSetChanged(); method the insert may not have actually happened as the content provider call to insert will be handled asynchronously.
An example could look something like this
#Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase sqlDB = mDB.getWritableDatabase();
int uriType = sURIMatcher.match(uri);
long id;
switch (uriType) {
case TEAMS:
id = sqlDB.replace(TeamModel.TEAM_TABLE_NAME, null, values);
break;
case CARS:
id = sqlDB.replace(CarModel.CAR_TABLE_NAME, null, values);
break;
case TEAM_ERRORS:
id = sqlDB.replace(TeamErrorModel.TEAMS_ERRORS_TABLE_NAME, null, values);
String teamId = values.get(TeamErrorModel.COL_TEAM_ID).toString();
String selection = TeamModel.COL_ID + " = ?";
String[] selectionArgs = {teamId};
setErrorFlagTeamModel(sqlDB, true, selection, selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null, false);
return Uri.parse(uri + "/" + id);
}
The first argument is the URI passed in to the insert method and will tell ALL adapters listening in on that particular uri to update their data.
The last argument (false) tells a sync adapter to ignore this change. I assume you are not using a sync adapter
All methods in your ContentProvider should call the notifyChange method in a similar way.
You may well find that the insert actually failed. so check that the records are actually being inserted.
UPDATE
As per comment below from #zapi
And you need to add cursor.setNotificationUri(contentresolver, uri)
inside the query method or the Cursor does not know for which uri
notification it has to listen
Since answering your question you have posted your content provider and I can now see that in fact as per the above quote this is in fact your missing link
I have to implement a listview in which my current data comes on top of the listview. Right now my recent data comes at the bottom and my first data is coming on the top of the listview. I'm attaching my work so far:
SearchActivity.java
public class SearchActivity extends Activity implements OnClickListener,
OnItemClickListener {
private EditText mHistoryNameEditText;
private Button mInsertButton;
private ListView mHistoryListView;
private ListAdapter mHistoryListAdapter;
private ArrayList<SearchHistoryDetails> searchArrayList;
private ArrayList<SearchHistoryDetails> HistoryObjArrayList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHistoryNameEditText = (EditText) findViewById(R.id.editText1);
mInsertButton = (Button) findViewById(R.id.button1);
mInsertButton.setOnClickListener(this);
mHistoryListView = (ListView) findViewById(R.id.names_lsitviews);
mHistoryListView.setOnItemClickListener(this);
searchArrayList = new ArrayList<SearchHistoryDetails>();
mHistoryListAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, populateList());
mHistoryListView.setAdapter(mHistoryListAdapter);
HistoryObjArrayList = new ArrayList<SearchHistoryDetails>();
}
#Override
public void onClick(View v) {
if (v.getId() == R.id.button1) {
String providedUgraduateName = mHistoryNameEditText.getText()
.toString();
SearchHistoryDetails undergraduateDetailsPojoObj = new SearchHistoryDetails();
undergraduateDetailsPojoObj.setuGraduateName(providedUgraduateName);
HistoryObjArrayList.add(undergraduateDetailsPojoObj);
insertUndergraduate(undergraduateDetailsPojoObj);
finish();
}
}
public void insertUndergraduate(
SearchHistoryDetails paraUndergraduateDetailsPojoObj) {
AndroidOpenDbHelper androidOpenDbHelperObj = new AndroidOpenDbHelper(
this);
SQLiteDatabase sqliteDatabase = androidOpenDbHelperObj
.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put(AndroidOpenDbHelper.COLUMN_NAME_UNDERGRADUATE_NAME,
paraUndergraduateDetailsPojoObj.getuGraduateName());
long affectedColumnId = sqliteDatabase.insert(
AndroidOpenDbHelper.TABLE_NAME_GPA, null, contentValues);
sqliteDatabase.close();
Toast.makeText(this,
"Values inserted column ID is :" + affectedColumnId,
Toast.LENGTH_SHORT).show();
}
public List<String> populateList() {
List<String> uGraduateNamesList = new ArrayList<String>();
AndroidOpenDbHelper openHelperClass = new AndroidOpenDbHelper(this);
SQLiteDatabase sqliteDatabase = openHelperClass.getReadableDatabase();
Cursor cursor = sqliteDatabase.query(
AndroidOpenDbHelper.TABLE_NAME_GPA, null, null, null, null,
null, null);
startManagingCursor(cursor);
while (cursor.moveToNext()) {
String ugName = cursor
.getString(cursor
.getColumnIndex(AndroidOpenDbHelper.COLUMN_NAME_UNDERGRADUATE_NAME));
SearchHistoryDetails ugPojoClass = new SearchHistoryDetails();
ugPojoClass.setuGraduateName(ugName);
searchArrayList.add(ugPojoClass);
uGraduateNamesList.add(ugName);
}
sqliteDatabase.close();
return uGraduateNamesList;
}
#Override
protected void onResume() {
super.onResume();
searchArrayList = new ArrayList<SearchHistoryDetails>();
mHistoryListAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, populateList());
mHistoryListView.setAdapter(mHistoryListAdapter);
}
#Override
protected void onStart() {
super.onStart();
searchArrayList = new ArrayList<SearchHistoryDetails>();
mHistoryListAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, populateList());
mHistoryListView.setAdapter(mHistoryListAdapter);
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Toast.makeText(getApplicationContext(), "Clicked on :" + arg2,
Toast.LENGTH_SHORT).show();
SearchHistoryDetails clickedObject = searchArrayList.get(arg2);
Bundle dataBundle = new Bundle();
dataBundle.putString("clickedUgraduateName",
clickedObject.getuGraduateName());
}}
This class helps me in getting the data from the database and populating it on the activity. My creating database class:
AndroidOpenDbHelper.java
public class AndroidOpenDbHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "allsearch_history_db";
public static final int DB_VERSION = 1;
public static final String TABLE_NAME_GPA = "search_table";
public static final String COLUMN_NAME_UNDERGRADUATE_NAME = "undergraduate_name_column";
public AndroidOpenDbHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
String sqlQueryToCreateUndergraduateDetailsTable = "create table if not exists "
+ TABLE_NAME_GPA
+ " ( "
+ BaseColumns._ID
+ " integer primary key autoincrement, "
+ COLUMN_NAME_UNDERGRADUATE_NAME
+ " text not null); ";
db.execSQL(sqlQueryToCreateUndergraduateDetailsTable);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion == 1 && newVersion == 2) {
// Upgrade the database
}
}}
This is the class from which I create database and table.
Now, the real deal is that, when I try to populate data from the database it comes as the first one on top and the latest one on down. I want to revert it. Any help will be appreciated in overcoming this problem.
There are a few different ways to do this. I recommend using the ORDER BY clause of your query:
Cursor cursor = sqliteDatabase.query(
AndroidOpenDbHelper.TABLE_NAME_GPA, null, null, null, null, null,
AndroidOpenDbHelper.COLUMN_NAME_UNDERGRADUATE_NAME + " DESC");
Also if you are only going to read from one column, your query should only request that column. Otherwise you are wasting resources querying unused columns of information:
Cursor cursor = sqliteDatabase.query(
AndroidOpenDbHelper.TABLE_NAME_GPA,
new String[] {AndroidOpenDbHelper.COLUMN_NAME_UNDERGRADUATE_NAME},
null, null, null, null,
AndroidOpenDbHelper.COLUMN_NAME_UNDERGRADUATE_NAME + " DESC");
Lastly, you may want to look into using a SimpleCursorAdapter which allows you to bind a query to a ListView with minimal code.
Addition
I took a closer look at your code and try this:
Cursor cursor = sqliteDatabase.query(
AndroidOpenDbHelper.TABLE_NAME_GPA, null, null, null, null, null,
BaseColumns._ID + " DESC");
Well i can suggest you to get the data from the database and add the items in the reverse order in the adapter that you are setting for populating the listview.
Consider this as the sample where you can get the values from the database which returns an arraylist.
Now consider this arraylist and add each item to the arrayadapter from the last like :
for(i=arraylist.size()-1;i>0;i--)
{
adapter.add(arraylist.get(i));
}
and after setting for the first time you can call
adapter.notifyDataSetChanged()
to refresh the list automatically.
Give a try to this