How to delete items from a database - java

I am making an app that stores a name and a mark in a database and it displays this in a listview. How can I delete an item of the listview and also of the database with a long press of the item in the listview??
Here is the code of the database helper:
public class PersonDatabaseHelper {
private static final String TAG = PersonDatabaseHelper.class.getSimpleName();
// database configuration
// if you want the onUpgrade to run then change the database_version
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "mydatabase.db";
public static String query;
// table configuration
private static final String TABLE_NAME = "person_table"; // Table name
private static final String PERSON_TABLE_COLUMN_ID = "_id"; // a column named "_id" is required for cursor
private static final String PERSON_TABLE_COLUMN_NAME = "person_name";
private static final String PERSON_TABLE_COLUMN_PIN = "person_pin";
private DatabaseOpenHelper openHelper;
private SQLiteDatabase database;
// this is a wrapper class. that means, from outside world, anyone will communicate with PersonDatabaseHelper,
// but under the hood actually DatabaseOpenHelper class will perform database CRUD operations
public PersonDatabaseHelper(Context aContext) {
openHelper = new DatabaseOpenHelper(aContext);
database = openHelper.getWritableDatabase();
}
public void insertData (String aPersonName, String aPersonPin) {
// we are using ContentValues to avoid sql format errors
ContentValues contentValues = new ContentValues();
contentValues.put(PERSON_TABLE_COLUMN_NAME, aPersonName);
contentValues.put(PERSON_TABLE_COLUMN_PIN, aPersonPin);
database.insert(TABLE_NAME, null, contentValues);
}
public Cursor getAllData () {
String buildSQL = "SELECT * FROM " + TABLE_NAME;
Log.d(TAG, "getAllData SQL: " + buildSQL);
return database.rawQuery(buildSQL, null);
}
// this DatabaseOpenHelper class will actually be used to perform database related operation
private class DatabaseOpenHelper extends SQLiteOpenHelper {
public DatabaseOpenHelper(Context aContext) {
super(aContext, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
// Create your tables here
String buildSQL = "CREATE TABLE " + TABLE_NAME + "( " + PERSON_TABLE_COLUMN_ID + " INTEGER PRIMARY KEY, " +
PERSON_TABLE_COLUMN_NAME + " TEXT, " + PERSON_TABLE_COLUMN_PIN + " TEXT )";
Log.d(TAG, "onCreate SQL: " + buildSQL);
sqLiteDatabase.execSQL(buildSQL);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
// Database schema upgrade code goes here
String buildSQL = "DROP TABLE IF EXISTS " + TABLE_NAME;
Log.d(TAG, "onUpgrade SQL: " + buildSQL);
sqLiteDatabase.execSQL(buildSQL); // drop previous table
onCreate(sqLiteDatabase); // create the table from the beginning
}
}
public void average() {
String query = "SELECT AVG("+PERSON_TABLE_COLUMN_PIN +") FROM "+TABLE_NAME;
database.rawQuery(query, null);
}
}

Well, since you have a unique ID associated with each entry in your database, you could delete based on that, like so:
public void deleteItem(int itemId){
this.getWritableDatabase().delete(TABLE_NAME, PERSON_TABLE_COLUMN_ID + "=" + itemId, null);
}
Then, when an item in your ListView is long-pressed, you could call that method to remove it from your database, and then call remove(Object) on your Adapter (or remove(int) on the List your Adapter uses), followed by notifyDataSetChanged() to ensure it updates the display correctly.
Edit: To answer your question about how to apply a long click listener to an item in your ListView, it depends on how you've implemented the Adapter. If it's's a custom adapter, you can simply set an onLongClickListener() to your root View (e.g. convertView). If you're not using that, you can try attaching an AdapterView.OnItemLongClickListener like this to your ListView:
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int position, long arg3) {
// get the data from your list at position, i.e. data.get(position)
// then pass that object / id to your database helper, e.g.
Person p = data.get(position);
personDatabaseHelper.deleteItem(p.getId());
data.remove(position); // or adapter.remove(p), depends on your implementation
adapter.notifyDataSetChanged(); // remove the object from your Adapter and notify it of the change
return true;
}
});
Edit 2: Using a custom Adapter
In your getView() method, add the following before returning convertView:
public View getView(final int position, View convertView, ViewGroup parent){
// your other stuff here
convertView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
Person p = getItem(position);
personDatabaseHelper.deleteItem(p.getId());
remove(p);
notifyDataSetChanged();
return true;
}
});
return convertView;
}

Related

how to delete a specific item from table in database?

I want to make a to-do list app, and I wanted to delete the item in the list by tapping the checkbox.
I tried to make a "deleteTask"(as you see in the code) method in the database class. Also, you can see the "populateListView"
method, it provides data from the database into listview, I use it to refresh after each time a task got deleted from the database.
public void deleteTask(String task) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, COL2 , new String[]{task});
}
public void populateListView() {
try {
mDataBaseHelper = new DataBaseHelper(MainActivity.this);
data = mDataBaseHelper.getData();
mArrayList = new ArrayList<>();
if (data.getCount() != 0) {
while (data.moveToNext()) {
mArrayList.add(data.getString(1));
ListAdapter listAdapter = new ArrayAdapter(MainActivity.this, R.layout.list_items, R.id.checkBox, mArrayList);
list = (ListView) findViewById(R.id.myListId);
list.setAdapter(listAdapter);
}
mDataBaseHelper.close();
} else {
toastMessage("the Database is empty");
}
}catch(Exception e){
Log.e(TAG, "populateListView: error"+e.getStackTrace() );
}
}
when the application gets started, I tapped the item that I want to delete, but I see that the items start to be deleted by order from above!
one by one each time I tapped any checkbox.
You want :-
public void deleteTask(String task) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_NAME, COL2 + "=?" , new String[]{task});
}
If you weren't trapping the error by using the try/catch using db.delete(TABLE_NAME, COL2 , new String[]{task}); you would get an exception along the lines of :-
java.lang.IllegalArgumentException: Too many bind arguments. 1 arguments were provided but the statement needs 0 arguments.
However
Assuming that the issue with deleting rows sequentially rather than according to the checked item(s), is likely due to the handling of the checked items. However, as the code for this is not provided it would only be guess work to know where in the code you are going wrong.
One thing is that you do not want to be creating a new listadapter instance every time you populate the ListView.
As a hint to handling a ListView, but deleting an item when it is long-clicked based upon the COL2 value, perhaps consider the following which has been based upon your code (but deletes according to long clicking an item) :-
public void populateLisView() {
mDataBaseHelper = new DataBaseHelper(this); //<<<<<<<<<< NOTE 1
list = (ListView) this.findViewById(R.id.myListId); //<<<<<<<<<< NOTE 1
data = mDataBaseHelper.getData(); //<<<<<<<<<< get the data to be listed
if (listadapter == null) { //<<<<<<<<<< Only need to instantiate one adapter when it has not bee instantiated
listadapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,android.R.id.text1,data); // for convenience using a stock layout
list.setAdapter(listadapter);
//<<<<<<<<<<< add the onItemLongClick listener
list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
mDataBaseHelper.deleteTaskByCol2(data.get(position)); //<<<<<<<<<< gets the value of the item according to it's position in the list
populateLisView(); //<<<<<<<<<< as the item has been deleted then refresh the Listview
return true; // flag the event as having been handled.
}
});
//<<<<<<<<<<< If the Adapter has been instantiated then refresh the ListView's data
} else {
listadapter.clear(); // Clear the data from the adapter
listadapter.addAll(data); // add the new changed data to the adapter
listadapter.notifyDataSetChanged(); // tell the adapter that the data has changed
}
}
NOTE 1
you would typically instantiate these variables once.
Check the comments
You may wish to edit your question to include how you are handling the check events.
The Full Working Example
DatabaseHelper.java
Note this may differ from yours a little
public class DataBaseHelper extends SQLiteOpenHelper {
public static final String DBNAME = "mydb";
public static final int DBVERSION = 1;
public static final String TABLE_NAME = "mytable";
public static final String COL1 = "col1";
public static final String COL2 = "col2";
SQLiteDatabase db;
private static final String CRT_MYTABLE_SQL = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME +
"(" +
COL1 + " TEXT, " +
COL2 + " TEXT" +
")";
public DataBaseHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
db = this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CRT_MYTABLE_SQL);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public long addMytableRow(String col1, String col2) {
ContentValues cv = new ContentValues();
cv.put(COL1,col1);
cv.put(COL2,col2);
return db.insert(TABLE_NAME,null,cv);
}
public ArrayList<String> getData() {
ArrayList<String> rv = new ArrayList<>();
Cursor csr = db.query(TABLE_NAME,null,null,null,null,null,null);
while (csr.moveToNext()) {
rv.add(csr.getString(csr.getColumnIndex(COL2)));
}
csr.close();
return rv;
}
public void deleteTaskByCol2(String task) {
db.delete(TABLE_NAME,COL2 + "=?",new String[]{task});
}
}
MainActivity.java
i.e. an example activity that is based upon your code, but according to the above :-
public class MainActivity extends AppCompatActivity {
DataBaseHelper mDataBaseHelper;
ArrayList<String> data;
ListView list;
ArrayAdapter<String> listadapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addSomeTestData();
populateLisView();
}
private void example001() {
}
public void populateLisView() {
mDataBaseHelper = new DataBaseHelper(this);
list = (ListView) this.findViewById(R.id.myListId);
data = mDataBaseHelper.getData();
if (listadapter == null) {
listadapter = new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,android.R.id.text1,data);
list.setAdapter(listadapter);
list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
//mDataBaseHelper.deleteTaskWrong(data.get(position)); // ooops
mDataBaseHelper.deleteTaskByCol2(data.get(position));
populateLisView();
return true;
}
});
} else {
listadapter.clear();
listadapter.addAll(data);
listadapter.notifyDataSetChanged();
}
}
private void addSomeTestData() {
if (mDataBaseHelper == null) {
mDataBaseHelper = new DataBaseHelper(this);
}
if (DatabaseUtils.queryNumEntries(mDataBaseHelper.getWritableDatabase(),DataBaseHelper.TABLE_NAME) > 0) return;
mDataBaseHelper.addMytableRow("Test1","Test1");
mDataBaseHelper.addMytableRow("Test2","Test2");
mDataBaseHelper.addMytableRow("Test3","Test3");
mDataBaseHelper.addMytableRow("Test4","Test4");
}
}
Note AddSomeTestData adds some data for testing/demonstration.
Result
When first run :-
After LongClicking Test 2
i.e. the long clicked item has been removed (from the list and the database) and the list refreshed.
Try to replace
db.delete(TABLE_NAME, COL2 , new String[]{task});
By
db.delete(TABLE_NAME, COL2 + " = ?" , new String[]{task});

The command : "DELETE FROM Table where ..." doesn't work

I cannot delete some data from my table in database.
I copy some SQLite code and paste it to my new project. It is quite simple.
I correct some code and it doesn't work.
I spend lots of time to solve this problem, but I couldn't make it.
Even no errors have occurred.
Except for the delete query, all other queries work pretty well.
This is based on android and java.
I tried to delete data by use these queries.
db.execSQL("DELETE FROM mca WHERE position=" + position + ";");
db.execSQL("DELETE FROM mca WHERE _id=" + id + ";");
db.execSQL("DELETE FROM mca WHERE member='" + member + "';");
I made _id, position and member have same value. So this codes make sense.
_id and position are INTEGER and member is TEXT.
This is MainActivity.java
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
MyRecyclerViewAdapter adapter;
MemberData md;
#Override
protected void onCreate(Bundle savedInstanstState) {
super.onCreate(savedInstanstState);
setContentView(R.layout.activity_main);
final DBHelper dbHelper = new DBHelper(getApplicationContext(), "test_alarm.db", null, 1);
ArrayList<MemberData> member;
member = new ArrayList<>();
for (int i = 1; i < 5; i++) {
try {
md = new MemberData(member.get(member.size() - 1).position + 1, i + "");
}catch(Exception e){
Log.d("error", e+"");
md = new MemberData(1, i+"");
}
member.add(md);
dbHelper.insert(md);
}
/*************** activate delete command ***************/
dbHelper.delete(2);
/*******************************************************/
// set up the RecyclerView
recyclerView = findViewById(R.id.my_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyRecyclerViewAdapter(this, member, dbHelper);
recyclerView.setAdapter(adapter);
}
}
class MemberData {
public int position;
public String member;
public MemberData(int position, String member) {
this.member = member;
this.position = position;
}
}
This is the SQLite function
public class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE mca (_id INTEGER PRIMARY KEY AUTOINCREMENT, member TEXT, position INTEGER);");
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void insert(MemberData md) {
SQLiteDatabase db = getWritableDatabase();
db.execSQL("INSERT INTO mca VALUES(null, '" + md.member + "', " + md.position + ");");
db.close();
}
public void delete(int position) {
SQLiteDatabase db = getWritableDatabase();
/********************* Delete query *******************/
db.execSQL("DELETE FROM mca WHERE position=" + position + ";");
/*******************************************************/
db.close();
}
public ArrayList<MemberData> getData() {
SQLiteDatabase db = getReadableDatabase();
ArrayList<MemberData> memberList = new ArrayList<>();
Cursor cursor = db.rawQuery("SELECT * FROM mca", null);
while (cursor.moveToNext()) {
memberList.add(new MemberData(cursor.getInt(1), cursor.getString(2)));
}
return memberList;
}
}
This is the adapter for RecyclerView.
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
private ArrayList<MemberData> mData;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
private DBHelper db;
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView myTextView;
public ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.textView);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// data is passed into the constructor
MyRecyclerViewAdapter(Context context, ArrayList<MemberData> data, DBHelper db) {
this.mInflater = LayoutInflater.from(context);
this.mData = data;
this.db = db;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.my_text_view, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String member = "member"+mData.get(position).member;
holder.myTextView.setText(member);
}
// total number of rows
#Override
public int getItemCount() {
return mData.size();
}
// convenience method for getting data at click position
String getItem(int id) {
return mData.get(id).member;
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
I just want to remove a certain value from table
db.execSQL("DELETE FROM mca WHERE position='" + position + "'");
db.execSQL("DELETE FROM mca WHERE _id='" + id + "'");
db.execSQL("DELETE FROM mca WHERE member='" + member + "'");
try this
be careful on the "'" and ";"
Always use ' while using a variable in SQLite queries. also remove the ";"
Eg: you have used position so define it like,
db.execSQL("DELETE FROM mca WHERE position='" + position + "'");
db.execSQL("DELETE FROM mca WHERE _id='" + id + "'");
db.execSQL("DELETE FROM mca WHERE member='" + member + "'");
use db.delete it return's 0 for failure 1 for success
public int delete(String position) {
SQLiteDatabase db = getWritableDatabase();
return db.delete("mca","position = ?",new String[] {position});
db.close();
}
You should Change your sql code like below.
When you are using variable inside a sql query you need to bind the variable value and the sql query as a single string.
try the code below.
db.execSQL("DELETE FROM mca WHERE position='" + position + "';");
db.execSQL("DELETE FROM mca WHERE _id='" + id + "';");
db.execSQL("DELETE FROM mca WHERE member='" + member + "';");

delete an item from listview from another activity through database

hi I want to remove(delete) an item from listview from a second activity which I previously saved from another activity. I found similar question on deleting row from database but I think there is a little bit change in my database and the one's given in other questions and answers. here is my code.
the activity from where I am saving and deleting the row. here I want to delete the row from listview.
case R.id.id_favorit:
// Add it to the DB and re-draw the ListView
myDb.insertRow("Atherosclerosis", 0, "");
Toast.makeText(getApplicationContext(), "Item Added to favorite list!", Toast.LENGTH_SHORT).show();
favClicked=true;
editor.putBoolean("menu_item", favClicked);
editor.commit();
invalidateOptionsMenu();
return true;
case R.id.id_favorit2:
myDb.deleteRow(??);
Toast.makeText(getApplicationContext(), "Item deleted from favorite list!", Toast.LENGTH_SHORT).show();
favClicked=false;
editor.putBoolean("menu_item", favClicked);
editor.commit();
invalidateOptionsMenu();
return super.onOptionsItemSelected(item);
}
return true;
}
here is my database
public class DBAdapter {
/////////////////////////////////////////////////////////////////////
// Constants & Data
/////////////////////////////////////////////////////////////////////
// For logging:
private static final String TAG = "DBAdapter";
// DB Fields
public static final String KEY_ROWID = "_id";
public static final int COL_ROWID = 0;
/*
* CHANGE 1:
*/
// TODO: Setup your fields here:
public static final String KEY_NAME = "name";
public static final String KEY_STUDENTNUM = "studentnum";
public static final String KEY_FAVCOLOUR = "favcolour";
// TODO: Setup your field numbers here (0 = KEY_ROWID, 1=...)
public static final int COL_NAME = 1;
public static final int COL_STUDENTNUM = 2;
public static final int COL_FAVCOLOUR = 3;
public static final String[] ALL_KEYS = new String[] {KEY_ROWID, KEY_NAME, KEY_STUDENTNUM, KEY_FAVCOLOUR};
// DB info: it's name, and the table we are using (just one).
public static final String DATABASE_NAME = "MyDb";
public static final String DATABASE_TABLE = "mainTable";
// Track DB version if a new version of your app changes the format.
public static final int DATABASE_VERSION = 2;
private static final String DATABASE_CREATE_SQL =
"create table " + DATABASE_TABLE
+ " (" + KEY_ROWID + " integer primary key autoincrement, "
/*
* CHANGE 2:
*/
// TODO: Place your fields here!
// + KEY_{...} + " {type} not null"
// - Key is the column name you created above.
// - {type} is one of: text, integer, real, blob
// (http://www.sqlite.org/datatype3.html)
// - "not null" means it is a required field (must be given a value).
// NOTE: All must be comma separated (end of line!) Last one must have NO comma!!
+ KEY_NAME + " text not null, "
+ KEY_STUDENTNUM + " integer not null, "
+ KEY_FAVCOLOUR + " string not null"
// Rest of creation:
+ ");";
// Context of application who uses us.
private final Context context;
private DatabaseHelper myDBHelper;
private SQLiteDatabase db;
/////////////////////////////////////////////////////////////////////
// Public methods:
/////////////////////////////////////////////////////////////////////
public DBAdapter(Context ctx) {
this.context = ctx;
myDBHelper = new DatabaseHelper(context);
}
// Open the database connection.
public DBAdapter open() {
db = myDBHelper.getWritableDatabase();
return this;
}
// Close the database connection.
public void close() {
myDBHelper.close();
}
// Add a new set of values to the database.
#SuppressLint("NewApi")
public long insertRow(String name, int studentNum, String favColour) {
Cursor c= db.query(true, DATABASE_TABLE, ALL_KEYS, KEY_NAME + "='" + name +"'", null, null, null, null, null, null);
if(c.getCount()>0){
return -1;
}
c.close();
/*
* CHANGE 3:
*/
// TODO: Update data in the row with new fields.
// TODO: Also change the function's arguments to be what you need!
// Create row's data:
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_NAME, name);
initialValues.put(KEY_STUDENTNUM, studentNum);
initialValues.put(KEY_FAVCOLOUR, favColour);
// Insert it into the database.
return db.insert(DATABASE_TABLE, null, initialValues);
}
// Delete a row from the database, by rowId (primary key)
public boolean deleteRow(long rowId) {
String where = KEY_ROWID + "=" + rowId;
return db.delete(DATABASE_TABLE, where, null) != 0;
}
public void deleteAll() {
Cursor c = getAllRows();
long rowId = c.getColumnIndexOrThrow(KEY_ROWID);
if (c.moveToFirst()) {
do {
deleteRow(c.getLong((int) rowId));
} while (c.moveToNext());
}
c.close();
}
// Return all data in the database.
#SuppressLint("NewApi")
public Cursor getAllRows() {
String where = null;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS,
where, null, null, null, KEY_ROWID + " DESC", null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
// Get a specific row (by rowId)
public Cursor getRow(long rowId) {
String where = KEY_ROWID + "=" + rowId;
Cursor c = db.query(true, DATABASE_TABLE, ALL_KEYS,
where, null, null, null, null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
// Change an existing row to be equal to new data.
public boolean updateRow(long rowId, String name, int studentNum, String favColour) {
String where = KEY_ROWID + "=" + rowId;
/*
* CHANGE 4:
*/
// TODO: Update data in the row with new fields.
// TODO: Also change the function's arguments to be what you need!
// Create row's data:
ContentValues newValues = new ContentValues();
newValues.put(KEY_NAME, name);
newValues.put(KEY_STUDENTNUM, studentNum);
newValues.put(KEY_FAVCOLOUR, favColour);
// Insert it into the database.
return db.update(DATABASE_TABLE, newValues, where, null) != 0;
}
/////////////////////////////////////////////////////////////////////
// Private Helper Classes:
/////////////////////////////////////////////////////////////////////
/**
* Private class which handles database creation and upgrading.
* Used to handle low-level database access.
*/
private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase _db) {
_db.execSQL(DATABASE_CREATE_SQL);
}
#Override
public void onUpgrade(SQLiteDatabase _db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading application's database from version " + oldVersion
+ " to " + newVersion + ", which will destroy all old data!");
// Destroy old database:
_db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
// Recreate new database:
onCreate(_db);
}
}
}
and now my listview another activity
private void populateListViewFromDB() {
Cursor cursor = myDb.getAllRows();
// Allow activity to manage lifetime of the cursor.
// DEPRECATED! Runs on the UI thread, OK for small/short queries.
startManagingCursor(cursor);
// Setup mapping from cursor to view fields:
String[] fromFieldNames = new String[]
{DBAdapter.KEY_NAME, DBAdapter.KEY_STUDENTNUM};
int[] toViewIDs = new int[]
{R.id.item_name};
// Create adapter to may columns of the DB onto elemesnt in the UI.
SimpleCursorAdapter myCursorAdapter =
new SimpleCursorAdapter(
this, // Context
R.layout.item_layout, // Row layout template
cursor, // cursor (set of DB records to map)
fromFieldNames, // DB Column names
toViewIDs // View IDs to put information in
);
// Set the adapter for the list view
ListView myList = (ListView) findViewById(R.id.favlistView1);
myList.setAdapter(myCursorAdapter);
}
private void registerListClickCallback() {
ListView myList = (ListView) findViewById(R.id.favlistView1);
//This code is for to delete the single item from the listview of favorite list
myList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
int arg2, final long arg3) {
Cursor cursor = myDb.getRow(arg3);
if (cursor.moveToFirst()) {
new AlertDialog.Builder(FavoriteDiseases.this)
.setTitle("Delete Item")
.setMessage("Do you want to delete this disease?")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// continue with delete
myDb.deleteRow(arg3);
populateListViewFromDB();
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do nothing
}
})
.show();
}
return true;
}
});
If you use LoaderManager and CursorLoader to load your data from the database, it will update the cursor, and you can update your ListView automatically when the database changes. Here is a link: Loaders

SimpleCursorAdapter does not load external sqlite database: "_id" error

The error says: column _id does not exists but the column is in the database (set as primary key) and this one is located in the external SD folder. I'm trying to return the values contained in the database on the initial load of the activity but it seems like the cursor is not returning anything.
public class ComponentsDbAdapter {
public static final String COLUMN_ID = "_id";
public static final String COLUMN_SUBSTRUCTURE = "substructure";
public static final String COLUMN_TYPE = "type";
public static final String COLUMN_ORDERNUM = "ordernum";
public static final String COLUMN_INSTALLATION = "installation";
private static final String TAG = "ComponentsDbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private static final String DATABASE_PATH = Environment.getExternalStorageDirectory().getAbsoluteFile()+ "/DATABASE_BACKUP/IMPORTED/";
private static final String DATABASE_NAME = "android.db";
private static final String TABLE_NAME = "TAB_WORKSCPE";
private static final int DATABASE_VERSION = 1;
private final Context mCtx;
public ComponentsDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_PATH+DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.query(TABLE_NAME, new String[] {COLUMN_ID, COLUMN_SUBSTRUCTURE, COLUMN_TYPE, COLUMN_ORDERNUM, COLUMN_INSTALLATION}, null, null, null, null, null);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
public ComponentsDbAdapter(Context ctx) {
this.mCtx = ctx;
}
public void close() {
if (mDbHelper != null) {
mDbHelper.close();
}
}
public Cursor fetchComponentsByName(String inputText) throws SQLException {
Log.w(TAG, inputText);
Cursor mCursor = null;
if (inputText == null || inputText.length () == 0) {
mCursor = mDb.query(TABLE_NAME, new String[] {COLUMN_ID, COLUMN_SUBSTRUCTURE, COLUMN_TYPE, COLUMN_ORDERNUM, COLUMN_INSTALLATION}, null, null, null, null, null);
} else {
mCursor = mDb.query(true, TABLE_NAME, new String[] {COLUMN_ID, COLUMN_SUBSTRUCTURE, COLUMN_TYPE, COLUMN_ORDERNUM, COLUMN_INSTALLATION}, COLUMN_TYPE + " like '%" + inputText + "%'", null, null, null, null, null);
}
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
public Cursor fetchAllComponents() {
Cursor mCursor = mDb.query(TABLE_NAME, new String[] {COLUMN_ID, COLUMN_SUBSTRUCTURE, COLUMN_TYPE, COLUMN_ORDERNUM, COLUMN_INSTALLATION}, null, null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
}
public class AndroidListViewCursorAdaptorActivity extends Activity {
private ComponentsDbAdapter dbHelper;
private SimpleCursorAdapter dataAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
dbHelper = new ComponentsDbAdapter(this);
dbHelper.open();
//Generate ListView from SQLite Database
displayListView();
}
private void displayListView() {
Cursor cursor = dbHelper.fetchAllComponents();
// The desired columns to be bound
String[] columns = new String[] {
ComponentsDbAdapter.COLUMN_SUBSTRUCTURE,
ComponentsDbAdapter.COLUMN_TYPE,
ComponentsDbAdapter.COLUMN_ORDERNUM,
ComponentsDbAdapter.COLUMN_INSTALLATION
};
// the XML defined views which the data will be bound to
int[] to = new int[] {
R.id.inst,
R.id.subdt,
R.id.type,
R.id.ordernum,
};
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
dataAdapter = new SimpleCursorAdapter(
this,
R.layout.country_info,
cursor,
columns,
to,
0);
ListView listView = (ListView) findViewById(R.id.listView1);
// Assign adapter to ListView
listView.setAdapter(dataAdapter);
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 state's capital from this row in the database.
String compSubdt = cursor.getString(cursor.getColumnIndexOrThrow("subdt"));
Toast.makeText(getApplicationContext(), compSubdt, Toast.LENGTH_SHORT).show();
}
});
EditText myFilter = (EditText) findViewById(R.id.myFilter);
myFilter.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
}
public void beforeTextChanged(CharSequence s, int start,int count, int after) {
}
public void onTextChanged(CharSequence s, int start,int before, int count) {
dataAdapter.getFilter().filter(s.toString());
}
});
dataAdapter.setFilterQueryProvider(new FilterQueryProvider() {
public Cursor runQuery(CharSequence constraint) {
return dbHelper.fetchComponentsByName(constraint.toString());
}
});
}
}
It doesn't appear from your code that you've created the table yet, so no columns will be found.
You do this within the onCreate method by creating a query to create the table. In your code you appear to be doing a select rather than create.
private static final String TABLE_CREATE = "create table "
+ TABLE_NAME
+ "("
+ COLUMN_ID + " integer primary key autoincrement, "
+ COLUMN_TYPE + " text not null default '', "
+ COLUMN_ORDERNUM + " integer not null default 0, "
+ COLUMN_INSTALLATION + " integer not null default 0, "
+ COLUMN_SUBSTRUCTURE + " text not null default ''"
+ ");";
#Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(TABLE_CREATE);
}
To store this on the external storage, you'll need to override getDatabasePath(...). A similar solution is here https://stackoverflow.com/a/8385537/935779
#Override
public File getDatabasePath(String name) {
// reference where you would like the file to be here.
File result = new File(getExternalFilesDir(null), name);
return result;
}
I believe you'll want to override this with your Application class since it's a member of ContextWrapper.
The method getDatabaseFile(...) is used inside of openOrCreateDatabase(...) to determine the location.
Alternatively you could just override openOrCreateDatabase(...) and set the file location there.
I don't think you can change or even specify the location of the database, only the name.
Leave off the path and don't try to put it in External Storage - let Android determine the path.
Ok, this took me almost week and a lot of stress but here is the solution. I started to go through a lot of tutorials and got it working in this one:
http://www.mysamplecode.com/2012/11/android-database-content-provider.html
I extracted the database from the virtual device and manually added more data. Then copied the database to the desired folder on my device folder (Its just to make sure the database consistency/columns are exactly the same). Then changed MyDatabaseHelper class as follows:
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_PATH = Environment.getExternalStorageDirectory().getAbsoluteFile()+ "/MYFOLDER/";
private static final String DATABASE_NAME = "TheWorld.db";
private static final int DATABASE_VERSION = 1;
MyDatabaseHelper(Context context) {
super(context, DATABASE_PATH+DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
CountriesDb.onCreate(db);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
CountriesDb.onUpgrade(db, oldVersion, newVersion);
}
}
Don't forget to add permissions to your manifest:
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Done!
If you read through the posts above the answer is based on Kirks advice so reading his recommended link helps. I still have more tests to do just in case my database structure was wrong before.

sqlite + listview + new Activity: close() was never explicitly called on database?

I have made an app that has 3 activities.
In the fisrt activity(Import) i just import some values to a sqlite database.
This is my DatabaseHelper class:
public class DatabaseHelper_bp extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "bpDB";
private static final int DATABASE_VERSION = 1;
// Database creation sql statement
private static final String DATABASE_CREATE = "create table bp_import ( _id integer primary key, datetime text not null, systolic text not null, diastolic text not null, pulses text not null, notes text not null);";
public DatabaseHelper_bp(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Method is called during creation of the database
#Override
public void onCreate(SQLiteDatabase database) {
database.execSQL(DATABASE_CREATE);
}
// Method is called during an upgrade of the database,
#Override
public void onUpgrade(SQLiteDatabase database, int oldVersion,
int newVersion) {
Log.w(DatabaseHelper_bp.class.getName(),
"Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
database.execSQL("DROP TABLE IF EXISTS bp_import");
onCreate(database);
}
}
And my DAO class for my measures/values:
public class BpDAO {
private DatabaseHelper_bp dbHelper;
private SQLiteDatabase database;
/**
* bp table related constants.
*/
public final static String bp_TABLE = "bp_import";
public final static String bp_ID = "_id";
public final static String bp_DT = "datetime";
public final static String bp_SYS = "systolic";
public final static String bp_DIA = "diastolic";
public final static String bp_PUL = "pulses";
public final static String bp_NOT = "notes";
/**
*
* #param context
*/
public BpDAO(Context context) {
dbHelper = new DatabaseHelper_bp(context);
database = dbHelper.getWritableDatabase();
}
/**
* \ Creates a new blood pressure measure
*
* #param datetime
* #param systolic
* #param diastolic
* #param pulses
* #param notes
* #return
*/
public long importBP(String datetime, String systolic, String diastolic,
String pulses, String notes) {
ContentValues values = new ContentValues();
values.put(bp_DT, datetime);
values.put(bp_SYS, systolic);
values.put(bp_DIA, diastolic);
values.put(bp_PUL, pulses);
values.put(bp_NOT, notes);
return database.insert(bp_TABLE, null, values);
}
public void close() {
database.close();
}
/**
* Fetch all bp
*
* #return
*/
public Cursor fetchAll_bp() {
Cursor mCursor = database.query(true, bp_TABLE, new String[] { bp_SYS,
bp_DIA, bp_DT, bp_ID }, null, null, null, null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
}
In the second activity(History) i have a List that is populated by the database,all ok
Here is the code of 2 Activity(history):
public class HistoryActivity extends ListActivity {
private BpDAO dao;
private SimpleCursorAdapter dbAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
dao = new BpDAO(this);
Cursor bpList = dao.fetchAll_bp();
String[] from = new String[] { BpDAO.bp_SYS, BpDAO.bp_DIA, BpDAO.bp_DT };
int[] target = new int[] { R.id.bpSysHolder, R.id.bpDiaHolder,
R.id.bpDtHolder };
dbAdapter = new SimpleCursorAdapter(this, R.layout.history_bp, bpList,
from, target);
setListAdapter(dbAdapter);
}
#Override
public void onListItemClick(ListView l, View view, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, view, position, id);
Log.d("BPT", "Selected bp id =" + id);
// log says that i have selected an item with id : 11
Cursor selectedBpDetails = (Cursor) l.getItemAtPosition(position);
String bp_DT = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_DT));
String bp_SYS = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_SYS));
String bp_DIA = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_DIA));
String bp_PUL = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_PUL));
String bp_NOT = selectedBpDetails.getString(selectedBpDetails
.getColumnIndex(BpDAO.bp_NOT));
Log.d("BPT", "Selected bp details = { date=" + bp_DT + ", systolic="
+ bp_SYS + ", diastolic=" + bp_DIA + ", pulses=" + bp_PUL
+ ", notes=" + bp_NOT + " }");
Intent intent = new Intent(HistoryActivity.this, FromHistory.class);
intent.putExtra("bp_SYS", bp_SYS);
intent.putExtra("bp_DIA", bp_DIA);
intent.putExtra("bp_DT", bp_DT);
intent.putExtra("bp_PUL", bp_PUL);
intent.putExtra("bp_NOT", bp_NOT);
startActivity(intent);
}
}
When i click on a list item i start a new activity that i show all the infos of the measure from the database.
But i have in logcat:
1.close() was never explicitly called on database
2.android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
3.E/System(561): java.lang.IllegalStateException: Don't have database lock!
I have seen some other questions but didn't manage to find how to close it for my situation.
(You should close your Cursors when you are done with them as the others have pointed out, but...)
The error is telling you that you need to close your SQLiteDatabase. Add this method to your BpDAO class:
public void close() {
database.close();
}
And whenever you create a new BpDAO object in any Activity you need to call close(), you can do this as soon as you are done or in onDestroy():
#Override
protected void onDestroy() {
super.onDestroy();
dao.close();
}
When you are done with cursor you need to close()
Example:
selectedBpDetails.close();
Either you close the cursor directly after the fetching of your data by calling close() on it, or you can override the onDestroy method for your activity and then in the implementation of this method you close the cursor(s) that you have opened.
public class HistoryActivity extends ListActivity {
// ...
Cursor bpList;
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
bpList = dao.fetchAll_bp();
// ...
}
#Override
protected void onDestroy() {
super.onDestroy();
bpList.close();
}
#Override
public void onListItemClick(ListView l, View view, int position, long id) {
// ...
Cursor selectedBpDetails = (Cursor) l.getItemAtPosition(position);
// ...
selectedBpDetails.close();
}
// ...
}

Categories