removing, restoring items in ListView and database - android

I have a ListView with items that are added dynamically. When an item is added, it is added to the ListView and also inserted into a SQLite Database so that the items in the list can be saved. I can also remove specific items by getting the postion if the item and then removing it with that information.
This is how I add items (I use multiple classes):
In DataModel.class:
public void addItem(Object data) {
String string = String.valueOf(data);
mPlanetsList.add(createPlanet("planet", string));
History history = new History();
history.getDataHashMap().put("planet", data);
history.addToHistoryDB();
mHistoryList.add(history);
if (null != mOnItemAddHandler) {
mOnItemAddHandler.onItemAdded(data);
}
}
In History.class:
public void addToHistoryDB() {
MySQLiteOpenHelper mDbHelper = MySQLiteOpenHelper.getInstance();
SQLiteDatabase db = mDbHelper.getWritableDatabase();
ContentValues values = getContentValues();
rawId = (int) db.insert(TABLE_NAME, COL_ID, values);
db.close();
}
This is how I remove items:
In DataModel.class:
public void removeItem(int index) {
if (mPlanetsList == null || index < 0 || index >= mPlanetsList.size()) {
return;
}
// remove from mPlanetList
mPlanetsList.remove(index);
History history = mHistoryList.get(index);
mHistoryList.remove(index);
if (null != history) {
history.remove();
history = null;
}
// notify, the HistoryFragment will update view
if (null != mOnItemAddHandler) {
mOnItemAddHandler.onItemRemove(index);
}
In History.class:
public void remove() {
MySQLiteOpenHelper mDbHelper = MySQLiteOpenHelper.getInstance();
SQLiteDatabase db = mDbHelper.getWritableDatabase();
int r = db.delete(TABLE_NAME, "_id = ?", // delete the int r ??
new String[] { String.valueOf(rawId) });
db.close();
}
When the app in removed from the 'recent apps' or is restarted, initList() is called which restored the ListView items from the Database.
This is the code:
DataModel:
private void initList() {
mHistoryList = History.getList();
for (int i = 0; i < mHistoryList.size(); i++) {
Object obj = mHistoryList.get(i).getDataHashMap().get("planet");
mPlanetsList.add(createPlanet("planet", String.valueOf(obj)));
}
}
History:
public static ArrayList<History> getList() {
Cursor cursor = null;
try {
MySQLiteOpenHelper mDbHelper = MySQLiteOpenHelper.getInstance();
SQLiteDatabase db = mDbHelper.getWritableDatabase();
String sql = "select * from " + History.TABLE_NAME;
ArrayList<History> list = new ArrayList<History>();
cursor = db.rawQuery(sql, null);
if (cursor != null) {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor
.moveToNext()) {
History item = new History();
item.fromCuror(cursor);
list.add(item);
}
}
return list;
} finally {
if (null != cursor && Integer.parseInt(Build.VERSION.SDK) < 14) {
cursor.close();
}
}
}
This method works fine as long as the order of the list is not changed - I can add items and removes items and it all works perfectly. However, I would like items to be added to the top of the list rather than the bottom.
So I read around on how to add items to the top of a ListView and found that by adding a 0 as the position when adding the item, the new items go to the top of the list.
mPlanetsList.add(0, createPlanet("planet", string)); // I put the 0 in wherever the item is added eg when adding from the database
When I do this, however, the items viewed/deleted in the ListView do not continue to correspond with the data in the Database. For example, Lets say I add three items to the List: dog then cat then horse. The ListView shows them in the correct order (horse at the top). If I then delete an item, lets say: cat , the ListView updates and everyting is good. But if I then restart the app, initList() is called. This is where the problem occurs - It is not cat that is removed from the list, it is horse or dog.
Possible points where I think the problem could be:
a) in the initList() - It is not adding the correct items
b) in the removeItem() - It is not removing the correct items from the Database.
c) in the getList() - maybe something with the cursor???
This think b) is more likely but I don't know where the problem is exactly or what to change it too.
EDIT:
After a little testing, I found that I was right that b) is where it goes wrong.
The steps to reproduce:
Create three items: cat then dog then horse. The ListView shows them in the correct order ie horse at the top, cat at the bottom. The Database shows them with cat at the top, horse at the bottom.
When I delete horse (top of ListView, bottom of Database) the ListView updates correctly, but in the Database it is not horse that has been deleted but in fact cat.
So because of the wrong removal, when the Database is used to restore the ListView, the ListView appears wrong.
I hope this makes things clearer!
EDIT 2: This is how I create my table:
public static final String TABLE_NAME = "history_table";
public static final String COL_TITLE = "title";
public static final String COL_CONTENT = "content";
public static final String COL_DATE = "date";
public static final String COL_TYPE = "type";
public static final String COL_ONGOING = "ongoing";
public static final String COL_DATA = "data";
public static final String COL_ID = "_id";
public static final String DATABASE_CREATE = "create table " + TABLE_NAME
+ "(" + COL_ID + " integer primary key autoincrement, " + COL_TITLE
+ " text not null, " + COL_CONTENT + " text not null, " + COL_DATE
+ " text not null, " + COL_TYPE + " text not null, " + COL_ONGOING
+ " text not null, " + COL_DATA + " text not null );";
This is getContentValues():
public ContentValues getContentValues() {
ContentValues values = new ContentValues();
values.put(History.COL_TITLE, "MyTitle");
values.put(History.COL_CONTENT, "MyContent");
values.put(History.COL_DATE, "Date placeholder");
values.put(History.COL_TYPE, "QuickNote");
values.put(History.COL_ONGOING, "Ongoing placeholder");
values.put(History.COL_DATA, new JSONObject(mDataHashMap).toString());
return values;
}
EDIT 3:
I have basically narrowed it down to the fact that because the order of items in the ListView and in the Database are different, deleting items by their postition in the list does not work. So would a possible solution would be to invert the order of items in the database to match the ListView (good idea / possible ?).
EDIT 3.1:
https://stackoverflow.com/a/7348117/2442638
This order by descending may help. I don't know where I should put it though
EDIT 3.5:
I now have the ordering working. The deleting very nearly works, but there is now a problem that the first deletion doesn't work. The rest work after that. I am sorting by the _id and as that is autoincrement maybe it starts at 1 or 0 and the list starts at the other. I will do more research

There are two list in the app: mHistoryList and mPlanetsList, You should keep the order of the data itmes in them are the same.
You can add items to the top of listview by calling the method addItem in DataModel:
public void addItem(Object data) {
History history = new History();
history.getDataHashMap().put("planet", data);
history.addToHistoryDB();
mHistoryList.add(0, history);
mPlanetsList.add(0, history.createPlanet());
if (null != mOnItemAddHandler) {
mOnItemAddHandler.onItemAdded(data);
}
}
Then the new data will be at the top of the listview.
After app restart, the code below will be called:
private void initList() {
mHistoryList = History.getList();
for (int i = 0; i < mHistoryList.size(); i++) {
mPlanetsList.add(mHistoryList.get(i).createPlanet());
}
}
We should make sure the data from History.getList(); has the same order, in another word, the new data time in the head of the list.
So we should change the code to (order by _id desc):
public static ArrayList<History> getList() {
Cursor cursor = null;
try {
MySQLiteOpenHelper mDbHelper = MySQLiteOpenHelper.getInstance();
SQLiteDatabase db = mDbHelper.getWritableDatabase();
// order by _id desc
String sql = "select * from " + History.TABLE_NAME + " order by _id desc";
ArrayList<History> list = new ArrayList<History>();
cursor = db.rawQuery(sql, null);
if (cursor != null) {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
History item = new History();
item.fromCuror(cursor);
list.add(item);
}
}
return list;
} finally {
if (null != cursor && Integer.parseInt(Build.VERSION.SDK) < 14) {
cursor.close();
}
}
}

Related

Store SQLite query result in a String array

How can I save a query result in a String array?
The query is simple, it's got only one column i.e.:
SELECT NAME FROM MYTABLE
What I want is to store the ids in a String array so I can show them as clickable items in a ListView
Try this
String selectQuery = "SELECT * FROM table";
try {
Cursor cursor = db.rawQuery(selectQuery, null);
ArrayList<String> ids = new ArrayList<>();
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
String id = cursor.getString(cursor.getColumnIndex(KEY_ID));
ids.add(id);
} while (cursor.moveToNext());
}
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
Assuming you've already executed your query against a SQLiteDatabase object, and received a Cursor in return, you can iterate through the cursor and save the value of each row to a String[] array like so:
String[] names;
if (cursor.moveToFirst()) {
names = new String[cursor.getCount()];
int colIndex = cursor.getColumnIndex("NAME");
do {
names[cursor.getPosition()] = cursor.getString(colIndex);
} while (cursor.moveToNext());
}
Keep in mind that names will be null if no rows are returned, so make sure you do a null check.
create following method in SQLiteOpenHelper class
public List<String> getAllNames() {
List<String> retData = new ArrayList<String>();
String selectQuery = "SELECT NAME FROM MYTABLE";
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
if (cursor.moveToFirst()) {
do {
retData.add(cursor.getString(0));
} while (cursor.moveToNext());
}
return retData;
}
then assign this returned list to adapter
The issue with listing id's is that they tend to be meaningless to an end user. Really you want to display user meaningful data, e.g. a name, but to then be able to access the respective id to then efficiently act on a selection from the list presented to a user.
Using an ArrayList is frequently the cause of much frustration, as the list shows what is required but it's then found to be of little use when attempting to use the list beyond displaying data e.g. selecting an item to then do something such as delete or update (if the value is unique within the database it can be used).
As such an ArrayList<your_object> rather then an ArrayList<String> is generally more viable as the source of the List; a Cursor Adapter can also be used as data from the underlying row is easily obtained.
However, there is an issue, unless a Custom Array Adapter is utilised, when using an ArrayList in that the ArrayAdapter class uses the toString method of the object to retrieve the data that is displayed. The simple fix is to provide a suitable toString method in the object, if you don't you will get something long the lines of “SomeType#2f92e0f4”.
Example showing all 3
In the following working example :-
the database (mydb) has 1 table named mytable which has two columns _id (Note must be _id for a CursorAdapter)
There are 3 methods to get the 3 types of list (named accordingly) :-
getAllAsStringArrayList (gets ArrayList)
getAllAsMyTableObjectArrayList (gets ArrayList). Note uses the MyTableObject class (see note in class re overriding the default toString method)
getAllAsCursor
The App, when run, will have 3 lists, the left based upon the first ArrayList, the middle based upon the ArrayList and the last based upon the Cursor.
Clicking an item in any of the lists displays the respective name along with attempts to get the id.
The ArrayList, Left List, fails in this aspect as it can only get the position (i.e. the 4th parameter passed to the listener is the same value as the position).
The ArrayList, middle List, when getting the id from the object (which is retrieved via the getItem(position) method of the Adapter) successfully retrieves the correct id, the 4th parameter is the same as the position, and should not be used.
The Cursor, Right List, retrieves the correct id both via the Cursor and the 4th parameter.
The Code
MyTableObject.java :-
public class MyTableObject {
private long id;
private String name;
public MyTableObject(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/*
NOTE toString method returns just the name
*/
#Override
public String toString() {
return name;
}
}
DatabaseHelper.java :-
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String DBNAME = "mydb";
public static final int DBVERSION = 1;
public static final String TB_MYTABLE = "mytable";
public static final String COl_MYTABLE_ID = BaseColumns._ID; //<<<< use standard android id column name
public static final String COL_MYTABLE_NAME = "_name";
private static final String mytable_crtsql =
"CREATE TABLE IF NOT EXISTS " + TB_MYTABLE +
"(" +
COl_MYTABLE_ID + " INTEGER PRIMARY KEY, " +
COL_MYTABLE_NAME + " TEXT " +
")";
SQLiteDatabase mDB;
public DatabaseHelper(Context context) {
super(context, DBNAME, null, DBVERSION);
mDB = this.getWritableDatabase();
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(mytable_crtsql);
}
#Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
public long addRow(String name) {
ContentValues cv = new ContentValues();
cv.put(COL_MYTABLE_NAME,name);
return mDB.insert(TB_MYTABLE,null,cv);
}
public ArrayList<String> getAllAsStringArrayList() {
ArrayList<String> rv = new ArrayList<>();
Cursor csr = mDB.query(
TB_MYTABLE,
null,
null,
null,
null,
null,
null
);
while (csr.moveToNext()) {
rv.add(csr.getString(csr.getColumnIndex(COL_MYTABLE_NAME)));
}
csr.close();
return rv;
}
public ArrayList<MyTableObject> getAllAsMyTableObjectArrayList() {
ArrayList<MyTableObject> rv = new ArrayList<>();
Cursor csr = mDB.query(
TB_MYTABLE,
null,
null,
null,
null,
null,
null
);
while (csr.moveToNext()) {
rv.add(new MyTableObject(
csr.getLong(csr.getColumnIndex(COl_MYTABLE_ID)),
csr.getString(csr.getColumnIndex(COL_MYTABLE_NAME))
)
);
}
csr.close();
return rv;
}
public Cursor getAllAsCursor() {
return mDB.query(
TB_MYTABLE,
null,
null,
null,
null,
null,
null
);
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
DatabaseHelper mDBHlpr;
ListView mListView01,mListVeiw02,mListView03;
ArrayAdapter<String> mAdapterStringArrayList;
ArrayAdapter<MyTableObject> mAdapterMyTableObjectArrayList;
SimpleCursorAdapter mAdapterCursor;
ArrayList<String> mMyTableListAsStrings;
ArrayList<MyTableObject> mMyTableAsObjects;
Cursor mMyTableListAsCursor;
Context mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mListView01 = this.findViewById(R.id.listview01);
mListVeiw02 = this.findViewById(R.id.listview02);
mListView03 = this.findViewById(R.id.listview03);
mDBHlpr = new DatabaseHelper(this);
mDBHlpr.addRow("Fred");
mDBHlpr.addRow("Bert");
mDBHlpr.addRow("Harry");
mDBHlpr.addRow("Fred");
//String Array List
mMyTableListAsStrings = mDBHlpr.getAllAsStringArrayList();
mAdapterStringArrayList = new ArrayAdapter<>(
this,
android.R.layout.simple_list_item_1,
mMyTableListAsStrings
);
mListView01.setAdapter(mAdapterStringArrayList);
//Object Array List
mMyTableAsObjects = mDBHlpr.getAllAsMyTableObjectArrayList();
mAdapterMyTableObjectArrayList = new ArrayAdapter<>(
this,
android.R.layout.simple_list_item_1,
mMyTableAsObjects
);
mListVeiw02.setAdapter(mAdapterMyTableObjectArrayList);
// Cursor
mMyTableListAsCursor = mDBHlpr.getAllAsCursor();
mAdapterCursor = new SimpleCursorAdapter(
this,
android.R.layout.simple_list_item_1,
mMyTableListAsCursor,
new String[]{DatabaseHelper.COL_MYTABLE_NAME},
new int[]{android.R.id.text1},
0
);
mListView03.setAdapter(mAdapterCursor);
mListView01.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
String name = mAdapterStringArrayList.getItem(position);
Toast.makeText(
mContext,
"Name is " + name +
". ID is " + String.valueOf(id) +
" (note may not match)",
Toast.LENGTH_SHORT
).show();
}
});
mListVeiw02.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
MyTableObject mytable = mAdapterMyTableObjectArrayList.getItem(position);
String name = mytable.getName();
long id_in_object = mytable.getId();
Toast.makeText(
mContext,
"Name is " + name +
". ID from object is " + String.valueOf(id_in_object) +
". ID from adapter is " + String.valueOf(id),
Toast.LENGTH_SHORT
).show();
}
});
mListView03.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Cursor csr = mAdapterCursor.getCursor(); // already positioned
String name = csr.getString(csr.getColumnIndex(DatabaseHelper.COL_MYTABLE_NAME));
long id_in_cursor = csr.getLong(csr.getColumnIndex(DatabaseHelper.COl_MYTABLE_ID));
Toast.makeText(
mContext,
"Name is " + name +
". ID from object is " + String.valueOf(id_in_cursor) +
". ID from adapter is " + String.valueOf(id),
Toast.LENGTH_SHORT
).show();
}
});
}
}

How to make a checkbox from information found in DataBase?

I have a table in DataBase, and I want to make a table.
Now it makes no sense that I will do a lot of CheckBox and show you only some of them according to the information in the table. I heard about the listview
But how do I do listview of checkbox I found an example of listview on the Internet and when I tried to insert large information, only half the information came in, so I was told to do adapter.
Do you have an example of how to do this?
It DatabaseHandler:
package budgetreport.com.budgetreport;
public class DatabaseHandler extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 4;
// Database Name
private static final String DATABASE_NAME = "Records_Item Purcashes";
// Contacts table name
private static final String TABLE_RECORDS = "Records";
// Contacts Table Columns names
private static final String KEY_ID = "ID";
private static final String KEY_PRICE = "Price";
private static final String KEY_ITEM = "Item";
private static final String KEY_DETAILS = "Details";
private static final String KEY_DATE = "Date";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " + TABLE_RECORDS + "("
+ KEY_ID + " INTEGER PRIMARY KEY,"
+ KEY_PRICE + " INTEGER," + KEY_ITEM + " TEXT,"
+ KEY_DETAILS + " TEXT, " + KEY_DATE + " TEXT" + ")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECORDS);
// Create tables again
onCreate(db);
}
// Adding new contact
public void addRecord(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId()); // Contact Name
values.put(KEY_PRICE, record.getPrice()); // Contact Name
values.put(KEY_ITEM, record.getItem()); // Contact Name
values.put(KEY_DETAILS, record.getDetails()); // Contact Name
values.put(KEY_DATE, record.getDetails()); // Contact Phone Number
// Inserting Row
db.insert(TABLE_RECORDS, null, values);
db.close(); // Closing database connection
}
// Getting single contact
public Record getRecord(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_RECORDS, new String[] { KEY_ID, KEY_PRICE,
KEY_ITEM, KEY_DETAILS, KEY_DATE }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
Record record = new Record(Integer.parseInt(cursor.getString(0)),
Integer.parseInt(cursor.getString(1)), cursor.getString(2), cursor.getString(3), cursor.getString(4));
// return contact
return record;
}
// Getting All Contacts
public List<Record> getAllContacts() {
List<Record> contactList = new ArrayList<Record>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
Record record = new Record();
record.setId(Integer.parseInt(cursor.getString(0)));
record.setPrice(Integer.parseInt(cursor.getString(1)));
record.setItem(cursor.getString(2));
record.setDetails(cursor.getString(3));
record.setDate(cursor.getString(4));
// Adding contact to list
contactList.add(record);
} while (cursor.moveToNext());
}
// return contact list
return contactList;
}
// Getting contacts Count
public int getRecordsCount() {
String countQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
// cursor.close();
// return count
return cursor.getCount();
}
// Updating single contact
public int updateContact(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId());
values.put(KEY_PRICE, record.getPrice());
values.put(KEY_DETAILS, record.getDetails());
values.put(KEY_DATE, record.getDate());
// updating row
return db.update(TABLE_RECORDS, values, KEY_ID + " = ?",
new String[] { String.valueOf(record.getPrice()) });
}
// Deleting single contact
public void deleteContact(Record record) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_RECORDS, KEY_ID + " = ?",new String[]
{String.valueOf(record.getPrice()) });
db.close();
}
}
Deletion of checked Items as per I want to erase the lines I have marked.
This is relatively simple to progress to.
It involves
- a) adding a method to the database helper to delete according to id.
- b) (i)amend the onClick listener to invoke the delete method (simple loop) and to then (ii)update the listview (after the loop).
However, the original custom adapter has some flaws in that the original cursor is retained via mCsr and no consideration was given to the number of checkboxes being changed when the Cursor is changed (swapped).
As such the adapter has had references to mCsr removed and replaced by the Cursor passed or via calling the getCursor method. Also the swapCursor() method has been overidden to adjust the number of elements of and re-initialise the elemnets (set to false), of mCheckBoxes.
a) The new deleteRecord method :-
public boolean deleteRecord(long id) {
SQLiteDatabase db = this.getWritableDatabase();
return (db.delete(TABLE_RECORDS,KEY_ID + "=?",new String[]{Long.toString(id)})> 0);
}
b)(i) onCLickListener amendments (note includes grouping all deletes into a single transaction) :-
// <<<<< DO IT BUTTON HANDLER i.e. get list of ID's for checked items
mDoItButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// get the ID's for the checked Items
mCheckedIdList = mMCA.getCheckedRecordIdList();
Toast.makeText(mContext,"You have " + mCheckedIdList.length + " Items checked.",Toast.LENGTH_SHORT).show();
//<<<< to delete
SQLiteDatabase db = mDBHandler.getWritableDatabase();
db.beginTransaction();
for (long id: mCheckedIdList) {
mDBHandler.deleteRecord(id);
}
db.setTransactionSuccessful();
db.endTransaction();
refreshListView();
}
});
b(ii) Update the Listview (new method in the Activity) :-
private void refreshListView() {
mCsr = mDBHandler.getAllRecords();
mMCA.swapCursor(mCsr);
}
Notes
this is added as a method to the activity.
mMCA.notifyDatasetChanged(); is an alternative (I personally prefer `swapCursor1 as it's more decsriptive).
The modified Custom Cursor Adapter should be :-
public class MyCustomCursorAdapter extends CursorAdapter {
private Context mContext;
private String[] mColumns;
private int[] mViews;
private int mLayout;
private boolean[] mCheckBoxStates;
private int mCheckBoxView;
// Constructor for the Custom Cursor Adapter
MyCustomCursorAdapter(Context context, int layout, Cursor csr, String[] from_columns, int[] to_views, int checkbox_view) {
super(context,csr, false);
mContext = context;
mLayout = layout;
mColumns = from_columns;
mViews = to_views;
mCheckBoxView = checkbox_view;
}
#Override
// Inflate the layout we are going to use (as passed via 2nd parameter)
public View newView(Context context, Cursor csr, ViewGroup parent) {
// Initialise an int array for the checkboxes (all will be 0)
mCheckBoxStates = new boolean[csr.getCount()];
return LayoutInflater.from(context).inflate(mLayout,parent,false);
}
#Override
// Tie the from_columns to the display views
public void bindView(View view, Context context, Cursor csr) {
final Cursor fcsr = csr;
// Place the data from the cursor into the respective View (TextView)
for (int i = 0; i < mColumns.length; i++) {
((TextView) view.findViewById(mViews[i])).setText(csr.getString(csr.getColumnIndex(mColumns[i])));
}
// Set the checkbox (note should be false, unless otherwise changed)
CheckBox currentCheckBox = (CheckBox) view.findViewById(mCheckBoxView);
currentCheckBox.setChecked(mCheckBoxStates[csr.getPosition()]);
currentCheckBox.setTag(new Long(csr.getLong(csr.getColumnIndex(DatabaseHandler.KEY_ID))));
//
currentCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
final int position = fcsr.getPosition();
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Store the checkbox status
mCheckBoxStates[position] = ((CheckBox) buttonView).isChecked();
int restore_cursor_position = fcsr.getPosition();
//Move the Cursor to the respective row
//NOTE! 1st position in Lisview is 1 but equates to cursor row 0 etc hence -1
fcsr.moveToPosition(position);
Toast.makeText(mContext,
"You Changed the CheckBox for row " +
Integer.toString(position + 1) +
" Item is " +
fcsr.getString(fcsr.getColumnIndex(DatabaseHandler.KEY_ITEM))
,
Toast.LENGTH_SHORT
).show();
//restore the Cursor's position
fcsr.moveToPosition(restore_cursor_position);
}
});
}
// get the list of items (the ID's as long) that have been checked.
public long[] getCheckedRecordIdList() {
Cursor csr = this.getCursor();
// using ArrayList as we can add as we don't yet know how many
ArrayList<Long> rva = new ArrayList<>();
// Just in case save the current position of the Cursor
int restore_cursor_position = csr.getPosition();
// Loop through the checkbox states
for (int i=0; i < mCheckBoxStates.length; i++) {
// If the checkbox reflected as being checked then handle, else ignore it
if (mCheckBoxStates[i]) {
// Move to the respective cursor row
csr.moveToPosition(i);
// get the respective ID and store in the arraylist
rva.add(csr.getLong(csr.getColumnIndex(DatabaseHandler.KEY_ID)));
}
}
// Done with the Cursor so re-position it
csr.moveToPosition(restore_cursor_position);
// Create the long array to be returned
long[] rv = new long[rva.size()];
// Populate the long array with the id's from the arraylist
for (int i=0; i < rva.size(); i++) {
rv[i] = rva.get(i);
}
// return the long[]
return rv;
}
#Override
public Cursor swapCursor(Cursor csr) {
mCheckBoxStates = new boolean[csr.getCount()];
for (int i=0; i < mCheckBoxStates.length; i++) {
mCheckBoxStates[i] = false;
}
return super.swapCursor(csr);
}
}
here's an example based upon you code.
1) The Activity's layout (i.e a ListView with an id of lv001) as file activity_main.xml :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.budgetreport.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_margin="10dp"
/>
<ListView
android:id="#+id/lv001"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
2) A layout for each row (Item in ListView terminology) as file listviewitem_record.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/record_price"
android:layout_width="0dp"
android:layout_weight="8"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="#+id/record_item"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="#+id/record_details"
android:layout_width="0dp"
android:layout_weight="20"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<TextView
android:id="#+id/record_date"
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
<CheckBox
android:id="#+id/record_checkbox"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
android:layout_margin="5dp"/>
</LinearLayout>
Note! the inclusion of a CheckBox, as well as TextViews for all columns.
3) To simplify matters I used this as DatabaseHandler.java :-
public class DatabaseHandler extends SQLiteOpenHelper {
// All Static variables
// Database Version
private static final int DATABASE_VERSION = 4;
// Database Name
public static final String DATABASE_NAME = "Records_Item Purcashes";
// Contacts table name
public static final String TABLE_RECORDS = "Records";
// Contacts Table Columns names
public static final String KEY_ID = "_id";
public static final String KEY_PRICE = "Price";
public static final String KEY_ITEM = "Item";
public static final String KEY_DETAILS = "Details";
public static final String KEY_DATE = "Date";
public DatabaseHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Creating Tables
#Override
public void onCreate(SQLiteDatabase db) {
String CREATE_CONTACTS_TABLE = "CREATE TABLE " +
TABLE_RECORDS +
"(" +
KEY_ID + " INTEGER PRIMARY KEY," +
KEY_PRICE + " INTEGER," +
KEY_ITEM + " TEXT," +
KEY_DETAILS + " TEXT, " +
KEY_DATE + " TEXT" +
")";
db.execSQL(CREATE_CONTACTS_TABLE);
}
// Upgrading database
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// Drop older table if existed
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECORDS);
// Create tables again
onCreate(db);
}
public void insertRecord(int price, String item, String details, String date) {
ContentValues cv = new ContentValues();
cv.put(KEY_PRICE,price);
cv.put(KEY_ITEM,item);
cv.put(KEY_DETAILS,details);
cv.put(KEY_DATE,date);
SQLiteDatabase db = this.getWritableDatabase();
db.insert(TABLE_RECORDS,null,cv);
}
public Cursor getAllRecords() {
SQLiteDatabase db = this.getWritableDatabase();
return db.query(TABLE_RECORDS,null,null,null,null,null,null);
}
/*
// Adding new contact
public void addRecord(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId()); // Contact Name
values.put(KEY_PRICE, record.getPrice()); // Contact Name
values.put(KEY_ITEM, record.getItem()); // Contact Name
values.put(KEY_DETAILS, record.getDetails()); // Contact Name
values.put(KEY_DATE, record.getDetails()); // Contact Phone Number
// Inserting Row
db.insert(TABLE_RECORDS, null, values);
db.close(); // Closing database connection
}
*/
/*
// Getting single contact
public AlphabeticIndex.Record getRecord(int id) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(TABLE_RECORDS, new String[] { KEY_ID, KEY_PRICE,
KEY_ITEM, KEY_DETAILS, KEY_DATE }, KEY_ID + "=?",
new String[] { String.valueOf(id) }, null, null, null, null);
if (cursor != null)
cursor.moveToFirst();
AlphabeticIndex.Record record = new AlphabeticIndex.Record(Integer.parseInt(cursor.getString(0)),
Integer.parseInt(cursor.getString(1)), cursor.getString(2), cursor.getString(3), cursor.getString(4));
// return contact
return record;
}
*/
/*
// Getting All Contacts
public List<AlphabeticIndex.Record> getAllContacts() {
List<AlphabeticIndex.Record> contactList = new ArrayList<AlphabeticIndex.Record>();
// Select All Query
String selectQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getWritableDatabase();
Cursor cursor = db.rawQuery(selectQuery, null);
// looping through all rows and adding to list
if (cursor.moveToFirst()) {
do {
AlphabeticIndex.Record record = new AlphabeticIndex.Record();
record.setId(Integer.parseInt(cursor.getString(0)));
record.setPrice(Integer.parseInt(cursor.getString(1)));
record.setItem(cursor.getString(2));
record.setDetails(cursor.getString(3));
record.setDate(cursor.getString(4));
// Adding contact to list
contactList.add(record);
} while (cursor.moveToNext());
}
// return contact list
return contactList;
}
*/
/*
// Getting contacts Count
public int getRecordsCount() {
String countQuery = "SELECT * FROM " + TABLE_RECORDS;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery(countQuery, null);
// cursor.close();
// return count
return cursor.getCount();
}
*/
/*
// Updating single contact
public int updateContact(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, record.getId());
values.put(KEY_PRICE, record.getPrice());
values.put(KEY_DETAILS, record.getDetails());
values.put(KEY_DATE, record.getDate());
// updating row
return db.update(TABLE_RECORDS, values, KEY_ID + " = ?",
new String[] { String.valueOf(record.getPrice()) });
}
*/
/*
// Deleting single contact
public void deleteContact(AlphabeticIndex.Record record) {
SQLiteDatabase db = this.getWritableDatabase();
db.delete(TABLE_RECORDS, KEY_ID + " = ?",new String[]
{String.valueOf(record.getPrice()) });
db.close();
}
*/
}
Notes about Changes to DatabaseHandler.java
The rowid alias has been changed from ID to _id, this is because CursorAdapter's need a column named _id and that column should be an alias for for the rowid (not going into technicalities here).
Instead of using a Record class I've commented out your code that uses this class, for my convenience.
I've changed TABLE and COLUMN names definitions to public, so they can be accessed elsewhere.
I've added two new methods insertRecord and getAllRecords:-
insertRecord just to add some data for testing/example
getAllRecords retrieves all rows as a Cursor, as opposed to an array.
NOTE! The database is not closed, this would result in an exception because a Cursor needs access to the database (opening and closing a database can be detrimental anyway).
4) The Activity itself (just displays the ListView after adding some data for the first run) as file MainActivity.java :-
public class MainActivity extends AppCompatActivity {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
Cursor mCsr;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) this.findViewById(R.id.lv001); // Get the ListView from it's id
mDBHandler = new DatabaseHandler(this); // Get an instance of the Database Handler
// Add some data but only if there is no data
if (DatabaseUtils.queryNumEntries(mDBHandler.getWritableDatabase(),DatabaseHandler.TABLE_RECORDS) < 1) {
mDBHandler.insertRecord(100,"Rock","A large stone.","31/12/2017");
mDBHandler.insertRecord(50,"Boulder","A Rock.","31/12/2018");
mDBHandler.insertRecord(322,"Soil","Loose earth.","31/7/2015");
mDBHandler.insertRecord(237,"Stone","A small rock.","31/8/2014");
mDBHandler.insertRecord(32,"Pebble","A small smooth stone.","11/12/2017");
}
// get all rows into a Cursor
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_PRICE,
DatabaseHandler.KEY_ITEM,
DatabaseHandler.KEY_DETAILS,
DatabaseHandler.KEY_DATE
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.record_price,
R.id.record_item,
R.id.record_details,
R.id.record_date
};
// get and instance of SimpleCursorAdapter
mSCA = new SimpleCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mListView.setAdapter(mSCA);
}
}
Result :-
Notes
This doesn't go into handling the checkboxes, this would likely need a CustomAdapter. There's plenty of tutorials for that e.g. how do i create a custom cursor adapter for a listview for use with images and text?.
Edit Amended to Include CheckBox handling
1) The Activity's layout activity_main.xml - Added a Button for getting Checked Items :-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mjt.budgetreport.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_margin="10dp"
/>
<Button
android:id="#+id/doitbutton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="DO ALL CHECKED ROWS"
/>
<ListView
android:id="#+id/lv001"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
2) The Custom Cursor Adapter MyCustomCursorAdapter.java
Signature similar to SimpleCursorAdapter BUT with an extra parameter for the id of the CheckBox.
Includes method getCheckedRecordIdList, which will return a list of Id's that have been checked.
Issues a Toast when a checkbox is checked or unchecked which displays the item, as in the ListView's Item # (not the Item in the table), clicked and the Item clicked (as in the Item value from the table).
:-
public class MyCustomCursorAdapter extends CursorAdapter {
private Context mContext;
private Cursor mCsr;
private String[] mColumns;
private int[] mViews;
private int mLayout;
private boolean[] mCheckBoxStates;
private int mCheckBoxView;
// Constructor for the Custom Cursor Adapter
MyCustomCursorAdapter(Context context, int layout, Cursor csr, String[] from_columns, int[] to_views, int checkbox_view) {
super(context,csr, false);
mContext = context;
mLayout = layout;
mCsr = csr;
mColumns = from_columns;
mViews = to_views;
mCheckBoxView = checkbox_view;
}
#Override
// Inflate the layout we are going to use (as passed via 2nd parameter)
public View newView(Context context, Cursor csr, ViewGroup parent) {
// Initialise an int array for the checkboxes (all will be 0)
mCheckBoxStates = new boolean[csr.getCount()];
return LayoutInflater.from(context).inflate(mLayout,parent,false);
}
#Override
// Tie the from_columns to the display views
public void bindView(View view, Context context, Cursor csr) {
// Place the data from the cursor into the respective View (TextView)
for (int i = 0; i < mColumns.length; i++) {
((TextView) view.findViewById(mViews[i])).setText(csr.getString(csr.getColumnIndex(mColumns[i])));
}
// Set the checkbox (note should be false, unless otherwise changed)
CheckBox currentCheckBox = (CheckBox) view.findViewById(mCheckBoxView);
currentCheckBox.setChecked(mCheckBoxStates[mCsr.getPosition()]);
currentCheckBox.setTag(new Long(mCsr.getLong(mCsr.getColumnIndex(DatabaseHandler.KEY_ID))));
//
currentCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
final int position = mCsr.getPosition();
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
// Store the checkbox status
mCheckBoxStates[position] = ((CheckBox) buttonView).isChecked();
int restore_cursor_position = mCsr.getPosition();
//Move the Cursor to the respective row
//NOTE! 1st position in Lisview is 1 but equates to cursor row 0 etc hence -1
mCsr.moveToPosition(position);
Toast.makeText(mContext,
"You Changed the CheckBox for row " +
Integer.toString(position + 1) +
" Item is " +
mCsr.getString(mCsr.getColumnIndex(DatabaseHandler.KEY_ITEM))
,
Toast.LENGTH_SHORT
).show();
//restore the Cursor's position
mCsr.moveToPosition(restore_cursor_position);
}
});
}
// get the list of items (the ID's as long) that have been checked.
public long[] getCheckedRecordIdList() {
// using ArrayList as we can add as we don't yet know how many
ArrayList<Long> rva = new ArrayList<>();
// Just in case save the current position of the Cursor
int restore_cursor_position = mCsr.getPosition();
// Loop through the checkbox states
for (int i=0; i < mCheckBoxStates.length; i++) {
// If the checkbox reflected as being checked then handle, else ignore it
if (mCheckBoxStates[i]) {
// Move to the respective cursor row
mCsr.moveToPosition(i);
// get the respective ID and store in the arraylist
rva.add(mCsr.getLong(mCsr.getColumnIndex(DatabaseHandler.KEY_ID)));
}
}
// Done with the Cursor so re-position it
mCsr.moveToPosition(restore_cursor_position);
// Create the long array to be returned
long[] rv = new long[rva.size()];
// Populate the long array with the id's from the arraylist
for (int i=0; i < rva.size(); i++) {
rv[i] = rva.get(i);
}
// return the long[]
return rv;
}
}
3) The amended MainActivity to use the Custom Adapter and to get the list of checked Records (displays number selected via Toast) - MainActivity.java
Changed/Added Lines/Methods are marked with <<<<<.
:-
public class MainActivity extends AppCompatActivity {
DatabaseHandler mDBHandler;
ListView mListView;
SimpleCursorAdapter mSCA;
MyCustomCursorAdapter mMCA; // <<<<<
Cursor mCsr;
Button mDoItButton;
Context mContext; //<<<<<
long[] mCheckedIdList; //<<<<<
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mContext = this;
mListView = (ListView) this.findViewById(R.id.lv001); // Get the ListView from it's id
mDoItButton = (Button) this.findViewById(R.id.doitbutton); //<<<<<
mDBHandler = new DatabaseHandler(this); // Get an instance of the Database Handler
// Add some data but only if there is no data
if (DatabaseUtils.queryNumEntries(mDBHandler.getWritableDatabase(),DatabaseHandler.TABLE_RECORDS) < 1) {
mDBHandler.insertRecord(100,"Rock","A large stone.","31/12/2017");
mDBHandler.insertRecord(50,"Boulder","A Rock.","31/12/2018");
mDBHandler.insertRecord(322,"Soil","Loose earth.","31/7/2015");
mDBHandler.insertRecord(237,"Stone","A small rock.","31/8/2014");
mDBHandler.insertRecord(32,"Pebble","A small smooth stone.","11/12/2017");
}
mDBHandler.increasePrice(1,213);
// get all rows into a Cursor
mCsr = mDBHandler.getAllRecords();
// Prepare a list of the columns to get the data from, for the ListViewt
String[] columns_to_get_data_from = new String[]{
DatabaseHandler.KEY_ID,
DatabaseHandler.KEY_PRICE,
DatabaseHandler.KEY_ITEM,
DatabaseHandler.KEY_DETAILS,
DatabaseHandler.KEY_DATE
};
// Prepare a list of the Views into which to place the data
int[] itemviews_to_place_data_in = new int[]{
R.id.record_id,
R.id.record_price,
R.id.record_item,
R.id.record_details,
R.id.record_date
};
// get and instance of SimpleCursorAdapter the listviewitem_record layout
mSCA = new SimpleCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
0);
// Tie the adapter to the Listview
mListView.setAdapter(mSCA);
// <<<<<< Alternate Custom Cursor Adapter
mMCA = new MyCustomCursorAdapter(this,
R.layout.listviewitem_record,
mCsr,
columns_to_get_data_from,
itemviews_to_place_data_in,
R.id.record_checkbox //<<<<<< id of the checkbox
);
// Hijack the Listview
mListView.setAdapter(mMCA); //<<<<<<
// <<<<< DO IT BUTTON HANDLER i.e. get list of ID's for checked items
mDoItButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// get the ID's for the checked Items
mCheckedIdList = mMCA.getCheckedRecordIdList();
Toast.makeText(mContext,"You have " + mCheckedIdList.length + " Items checked.",Toast.LENGTH_SHORT).show();
}
});
}
}
Note! you wouldn't typically have two adapters, but I left the SimpleCursorAdapter in for comparison.
Note! be a little patient, as if you click too much too soon you may get consfused.
Note! See other answer for deleting checked items.

Android SQLite: attempt to re-open an already-closed object

I'm trying to get certain book data from my Inventory table based on the ISBN.
However, I'm getting an error: "attempt to re-open an already-closed object". The error only occurs when I click a listView object, go to a different screen, go back to this page via "finish()", and then try to click on another listView object. I moved the String searchEntries[] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[position]); from the onClickListener to the previous for loop before the onClickListener and now it works.
Why does it not work if I try to getInventoryEntriesByISBN after returning to this activity from another activity via "finish()"?
The error occurs at SearchResultsScreen:
String searchEntries[] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[position]);
and by extension, occurs at InventoryAdapter:
Cursor cursor = db.rawQuery(query, new String[] {ISBN});
SearchResultsScreen.java
// Set up search array
for(int i = 0; i < isbn.length; i++)
{
searchArray.add(new InventoryItem(isbn[i], InventoryAdapter.getTitleAndAuthorByISBN(isbn[i])));
}
Toast.makeText(getApplicationContext(), "searchArray.size()="+searchArray.size(), Toast.LENGTH_LONG).show();
// add data in custom adapter
adapter = new CustomAdapter(this, R.layout.list, searchArray);
ListView dataList = (ListView) findViewById(R.id.list);
dataList.setAdapter(adapter);
// On Click ========================================================
dataList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String searchEntries[] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[position]);
InventoryAdapter.java (Most relevant parts)
public String[] getInventoryEntriesByISBN(String search, String ISBN)
{
String[] searchEntry = new String [9];
//Query
String query = "select * from INVENTORY where ISBN = ?";
Cursor cursor = db.rawQuery(query, new String[] {ISBN});
if(cursor.getCount()<1) // title Not Exist
{
cursor.close();
for(int i = 0; i < 9; i++)
searchEntry[i] = "Not Found";
return searchEntry;
}
cursor.moveToFirst();
//put data into respective variable
int publish = cursor.getInt(cursor.getColumnIndex("PUBLISH_DATE"));
String publishdate = ((Integer)publish).toString();
String title = cursor.getString(cursor.getColumnIndex("TITLE"));
String author = cursor.getString(cursor.getColumnIndex("AUTHOR"));
String callNumber = cursor.getString(cursor.getColumnIndex("CALL_NUMBER"));
int available = cursor.getInt(cursor.getColumnIndex("AVAILABLE_COUNT"));
String availablecount = ((Integer)available).toString();
int inventory = cursor.getInt(cursor.getColumnIndex("INVENTORY_COUNT"));
String inventorycount = ((Integer)inventory).toString();
int due = cursor.getInt(cursor.getColumnIndex("DUE_PERIOD"));
String dueperiod = ((Integer)due).toString();
int checkoutcount = cursor.getInt(cursor.getColumnIndex("COUNT"));
String count = ((Integer)checkoutcount).toString();
//combine variables into one array
searchEntry[0] = ISBN;
searchEntry[1] = title;
searchEntry[2] = author;
searchEntry[3] = publishdate;
searchEntry[4] = callNumber;
searchEntry[5] = availablecount;
searchEntry[6] = inventorycount;
searchEntry[7] = dueperiod;
searchEntry[8] = count;
cursor.close();
return searchEntry;
}
public String getTitleAndAuthorByISBN(String ISBN)
{
int entriesFound = getNumSearchEntries(ISBN);
if(entriesFound==0)
entriesFound = 1;
String searchEntry;
//Query
String query = "select * from INVENTORY where ISBN = ?";
Cursor cursor = db.rawQuery(query, new String[] {ISBN});
if(cursor.getCount()<1) // title Not Exist
{
cursor.close();
searchEntry = "Not Found";
return searchEntry;
}
cursor.moveToFirst();
//put data into respective variable
String title = cursor.getString(cursor.getColumnIndex("TITLE"));
String author = cursor.getString(cursor.getColumnIndex("AUTHOR"));
//combine variables into one String
searchEntry = title + " / " + author;
//close cursor and return
cursor.close();
return searchEntry;
}
DataBaseHelper.java
public class DataBaseHelper extends SQLiteOpenHelper
{
// Database Version
private static final int DATABASE_VERSION = 1;
// Database Name
private static final String DATABASE_NAME = "database.db";
// ============================ End Variables ===========================
public DataBaseHelper(Context context, String name, CursorFactory factory, int version)
{
super(context, name, factory, version);
}
public DataBaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
// Called when no database exists in disk and the helper class needs
// to create a new one.
#Override
public void onCreate(SQLiteDatabase _db)
{
_db.execSQL(LoginDataBaseAdapter.USER_TABLE_CREATE);
_db.execSQL(CheckOutDataBaseAdapter.CHECKOUT_TABLE_CREATE);
_db.execSQL(InventoryAdapter.INVENTORY_TABLE_CREATE);
_db.execSQL(StatisticsAdapter.STATISTICS_TABLE_CREATE);
}
// Called when there is a database version mismatch meaning that the version
// of the database on disk needs to be upgraded to the current version.
#Override
public void onUpgrade(SQLiteDatabase _db, int _oldVersion, int _newVersion)
{
// Log the version upgrade.
Log.w("TaskDBAdapter", "Upgrading from version " +_oldVersion + " to " +_newVersion + ", which will destroy all old data");
// Upgrade the existing database to conform to the new version. Multiple
// previous versions can be handled by comparing _oldVersion and _newVersion
// values.
// on upgrade drop older tables
_db.execSQL("DROP TABLE IF EXISTS " + LoginDataBaseAdapter.USER_TABLE_CREATE);
_db.execSQL("DROP TABLE IF EXISTS " + CheckOutDataBaseAdapter.CHECKOUT_TABLE_CREATE);
_db.execSQL("DROP TABLE IF EXISTS " + InventoryAdapter.INVENTORY_TABLE_CREATE);
_db.execSQL("DROP TABLE IF EXISTS " + StatisticsAdapter.STATISTICS_TABLE_CREATE);
// Create a new one.
onCreate(_db);
}
}
Check Database Connection before executing query:
if (!dbHelper.db.isOpen())
dbHelper.open();
you can also use cursor.requery(); for again same query.
and in last you have to close the cursor and database also.
cursor.close();
db.close();
Edited:
I have created DBHelper class which extends SQLiteOpenHelper, this class is inner class of DatabaseHelper class and that class have following methods.
/** For OPEN database **/
public synchronized DatabaseHelper open() throws SQLiteException {
dbHelper = new DBHelper(context);
db = dbHelper.getWritableDatabase();
return this;
}
/** For CLOSE database **/
public void close() {
dbHelper.close();
}
If you have still doubt then feel free to ping me. Thank you.
The error only occurs when I click an item, go to a different screen, go back to this page via "finish()", and then try to click on another listView object.
I moved the String searchEntries[] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[position]); from the onClickListener to the previous for loop before the onClickListener and now it works.
The correct SearchResultsScreen is below:
SearchResultsScreen.java
// Set up search array
final String Entries[][] = new String[isbn.length][9];
for(int i = 0; i < isbn.length; i++)
{
searchArray.add(new InventoryItem(isbn[i], InventoryAdapter.getTitleAndAuthorByISBN(isbn[i])));
Entries[i] = InventoryAdapter.getInventoryEntriesByISBN(searchQuery, isbn[i]);
}
Toast.makeText(getApplicationContext(), "searchArray.size()="+searchArray.size(), Toast.LENGTH_LONG).show();
// add data in custom adapter
adapter = new CustomAdapter(this, R.layout.list, searchArray);
ListView dataList = (ListView) findViewById(R.id.list);
dataList.setAdapter(adapter);
// On Click ========================================================
dataList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
String searchEntries[] = Entries[position];
This is your problem
if(cursor.getCount()<1) // title Not Exist
{
cursor.close();
for(int i = 0; i < 9; i++)
searchEntry[i] = "Not Found";
return searchEntry;
}
cursor.moveToFirst();
cursor.close();
Change to
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
{
String title = cursor.getString(cursor.getColumnIndex("TITLE"));
String author = cursor.getString(cursor.getColumnIndex("AUTHOR"));
//combine variables into one String
searchEntry = title + " / " + author;
}
public String[] getInventoryEntriesByISBN(String search, String ISBN)
{
String[] searchEntry = new String [9];
//Query
String query = "select * from INVENTORY where ISBN = ?";
Cursor cursor = db.rawQuery(query, new String[] {ISBN});
Add SQLiteDatabase db = this.getWritableDatabase(); in this code before executing the raw Query

Load database column with query result not working

I'm trying to load a database column with a cursor result for my quiz app. The reason for this is that i want to populate a list view with the questions in a each category so i set up this:
public void putValues(){
for (int i = 0; i < 18; i++) {
Cursor contentCursor = null;
contentCursor = mDB
.rawQuery("select count(*) from questions_en where used = 0 and category" + " = " + i, null);
if(contentCursor.getCount() >0 )
contentCursor.moveToFirst();
if (contentCursor.isAfterLast()) {
contentCursor.close();
mDB.close();
return;
}
int contentCursorInt = contentCursor.getInt(0);
Cursor upateCursor = null;
upateCursor = mDB.rawQuery("update categories_en set questions_count" + " = " + contentCursorInt + " where " + "_id" + " = " + i, null);
upateCursor.moveToNext();
upateCursor.close();
contentCursor.close();
}
}
so that when the user clicks an answer (on the question screen) used becomes 1(or any non-zero value) the query result changes. The above code works fine the very first time. Because i haven't set up the question screen, i added this query:
public void test(){
Cursor cus = mDB.rawQuery("update questions_en set used = 1 where category = 2 and _id = 146", null);
cus.close();
}
to my DB Adapter and then called this method from my MainActivty
#Override
public void onClick(View v) {
TestAdapter mTest = new TestAdapter(MainActivity.this);
mTest.createDatabase();
mTest.open();
mTest.test();
Log.d(DBHelper.TAG, " Worked ");
mTest.close();
}
});
But when i click on this and go to my ListActivity I expected the value of category 2 to have changed since the query had just been carried out again. But it doesn't reduce. I pulled out my DB from DDMS(file explorer) and i found out that the query to _id = 146 actually didn't change used to 1. Any help on what may be the cause?
Solve the problem with the help of this.
I just changed this:
public void test(){
Cursor cus = mDB.rawQuery("update questions_en set used = 1 where category = 2 and _id = 146", null);
cus.close();
}
to this
public void test(){
int id = 3;
ContentValues data = new ContentValues();
data.put(DBHelper.KEY_USED, "1");
mDB.update(DBHelper.KEY_QUESTIONS_TABLE, data, DBHelper.KEY_ID + " = " + id , null);
}

Android SQL query not ordering data

I have written a small android app that grabs some data and displays it in a ListView.
I want to have the list sorted in ascending order (no prob). But when I add a new item it stays at the bottom of the list even when the view/app is reloaded. It seems the only data that is being sorted is the entries that were created in the database OnCreate() method.
I'm not sure what code to provide but i'll start by showing you snippets of the DBAdapter class, then from the main app class.
Database construction query:
private static final String DATABASE_CREATE =
"create table "+ DATABASE_TABLE
+ "("
+ FIELD_ROWID+" integer primary key autoincrement, "
+ FIELD_NAME +" varchar(30) not null, " + FIELD_TELEPHONE + " varchar(20) not null, "
+ FIELD_ADDRESS + " text not null,"
+ FIELD_URL + " varchar(255) not null);";
Function to get list of data:
public Cursor getRestaurants()
{
Cursor result = null;
try{
result = db.query(DATABASE_TABLE, new String[] {FIELD_ROWID, FIELD_NAME}, null, null, null, null, FIELD_NAME+" ASC");
}
catch (Exception e)
{
Log.v("applog", e.getMessage());
}
return result;
}
Here is a snippet of the main method. Here you can see that I am calling the getRestaurants() function shown above. I'm stumped as to why the data isn't being sorted.
Any advice greatly appreciated. Thanks in advance.
public class Assignment2 extends ListActivity {
// Set up some global variables.
private static final int ADD_NEW_ID = Menu.FIRST;
private static final int CLOSE_APP_ID = ADD_NEW_ID+1;
private final DBAdapter db = new DBAdapter(this);
private static CursorAdapter curAdapter = null;
private static Cursor rawData = null;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
db.open(); // Open connection to restaurant db.
rawData = db.getRestaurants();
Log.v("applog", rawData.getCount()+" Restaurants loaded from DB.");
if(rawData.getCount() == 0)
{
Toast.makeText(getApplicationContext(), "No restaurants found.", Toast.LENGTH_SHORT).show();
}
try
{
/* The following two arrays are used to map DB fields to ListView items
* From a custom layout file.
*/
// Array of db fields to be used when converting cursor to ListView
String[] strFields = { "name", BaseColumns._ID };
// Array of listview id's to be used when populating the ListView
int[] intFields = { R.id.first };
curAdapter = new SimpleCursorAdapter(this, R.layout.row, rawData, strFields, intFields);
}
catch (Exception e)
{
Log.v("applog", e.getMessage());
}
// Apply the converter cursor to the current ListView
setListAdapter(curAdapter);
db.close(); // Close connection to restaurant db.
Im not sure exactly what your problem is but, it all looks good minus these lines of code I have when I get a callback from my new data insert
if(cursor!=null)cursor.requery();
adapter.notifyDataSetChanged();
Hopefully this will fix your issue.

Categories

Resources