Closing cursors across JAR boundaries - android

I use a content provider/resolver, have a separate project/lib that provides a number of DB helper methods. I have a second project/lib that does handy things with a cursor.
Imagine as such DB Helper Method (com.example.DBHelper):
public String[] dumpColumnTable() {
Cursor cursor = cr.query(MY_URI,
new String[] { FIELD },
null,
null,
null
);
return UtilMethods.createArrayFromCursor(cursor);
}
Then the Util methods (com.example.UtilMethods):
public static String[] createArrayFromCursor(Cursor cursor) {
return createArrayFromCursor(cursor, 0);
}
public static String[] createArrayFromCursor(Cursor cursor, int column) {
if (cursor == null) return null;
String[] strings = new String[cursor.getCount()];
if (cursor.moveToFirst()) {
int i=0;
do {
strings[i] = cursor.getString(column);
i++;
} while (cursor.moveToNext());
}
return strings;
}
Obviously the cursor isn't closed. This will leak a cursor. Logcat will give you that message.
SO, close it in the inner util function:
public static String[] createArrayFromCursor(Cursor cursor, int column) {
if (cursor == null) return null;
String[] strings = new String[cursor.getCount()];
if (cursor.moveToFirst()) {
int i=0;
do {
strings[i] = cursor.getString(column);
i++;
} while (cursor.moveToNext());
}
cursor.close();
return strings;
}
But logcat will still claim the cursor wasn't closed before finalize.
If instead, in the DB Helper method, I save the return value, close the cursor, then return it, I get no cursor leak/logcat message:
public String[] dumpColumnTable() {
Cursor cursor = cr.query(MY_URI,
new String[] { FIELD },
null,
null,
null
);
String[] toret = UtilMethods.createArrayFromCursor(cursor);
cursor.close();
return toret;
}
Why ? In debugging, the cursor is marked as close when the calls return. The call stack goes from my activity->db helper->util methods. The db helper and util methods are in separate projects from the activity.
Is there some pass by reference/value issue I'm missing, or crossing multiple JAR boundaries, or the casting of what is a SQLiteCursor to the generic Cursor type that I'm missing ?

Related

I need help for getting SQLite data

I use this method for retrieving my data
public String getdata() {
String[] columns= new String[]{RowId,RowBusinessName};
Cursor c=OurDatabase.query(TableName,columns,null,null,null,null,null);
String Result="";
int iRowId=c.getColumnIndex(RowId);
int iRowBusinessName=c.getColumnIndex(RowBusinessName);
for(c.moveToFirst();!c.isAfterLast();c.moveToNext()){
Result=Result+c.getString(iRowBusinessName)+"\n";
}
return Result;
}
How can I make it return structured data (id & business_name)?
I want to display every business_name in a single textview.
Please help
If I understand what you are trying to do, here is the solution if you want to get only 1 RowBusinessName returned as a String. (Hoping that your RowBusinessName is type String).
public String getdata(int rowId) {
String[] columns= new String[]{RowId,RowBusinessName};
Cursor cursor = db.query(TABLENAME, columns, RowId + "=?", new String[]{rowId + ""}, null, null, null, null);
String Result="";
if (cursor != null && cursor.moveToFirst()) {
// not required though
int rowId = cursor.getInt(cursor.getColumnIndexOrThrow(RowId));
String rowBusinessName = cursor.getString(cursor.getColumnIndexOrThrow(RowBusinessName));
result = rowBusinessName;
}
return result;
}
Now if you want a list of RowBusinessName, then you have to build a List<String> rather than appending it to Result. That's not really a good way!
public List<String> getAll() {
List<String> businessNameList = new ArrayList<String>();
String[] columns= new String[]{RowId,RowBusinessName};
Cursor c=OurDatabase.query(TableName,columns,null,null,null,null,null);
if (c != null && c.moveToFirst()) {
// loop until the end of Cursor and add each entry to Ticks ArrayList.
do {
String businessName = cursor.getString(cursor.getColumnIndexOrThrow(RowBusinessName));
if (businessName != null) {
businessNameList.add(businessName);
}
} while (c.moveToNext());
}
return businessNameList;
}
These are work around.
The appropriate answer would be to create an Object that holds id and businessName. That way, you build an object from DB and just return the entire Object.

return ArrayList<String> with specific record from SQLiteDataBase

I want to get values but the function always returns null. Even though I debug and there is value inside variable rv.
This is my method:
public ArrayList<String> getList(int id) {
try {
ArrayList<String> rv = new ArrayList<String>();
open();
Cursor c = db.rawQuery("select * from reviews where IDRE="+id, null);
if(c.moveToFirst() || c.getColumnCount()==1) {
rv.add(String.valueOf(c.getInt(c.getColumnIndex("IDRE"))));
rv.add(String.valueOf(c.getInt(c.getColumnIndex("ID_FK"))));
rv.add(c.getString(c.getColumnIndex("DATE")));
rv.add(c.getString(c.getColumnIndex("TYPE")));
rv.add(String.valueOf(c.getInt(c.getColumnIndex("COST"))));
rv.add(c.getString(c.getColumnIndex("SERVICE")));
rv.add(c.getString(c.getColumnIndex("ATMOSPHERE")));
rv.add(c.getString(c.getColumnIndex("OVERALL")));
rv.add(c.getString(c.getColumnIndex("COMMENT")));
}
c.close();
close();
return rv;
}catch(Exception e) {
return null;
}
}
Some logging would help determine if you're throwing an error and ending up in that catch block, as #Daniel Nugent is saying.
But I think the issue is with your if expression. c.moveToFirst is going to move your cursor to the first row of your data source, and then return true unless that data source is empty, so the only time that if block does not occur is when your data source is empty. The only way c.getColumnCount()==1 is having any effect on the evaluation of your expression is if you have a table with only one column and no rows. Let us know what you're trying to achieve with that, and add some logging, and we'll be better able to help you.
I have edited your code ...and given two example , you can refer any one...
public ArrayList<String> getList(int id) {
try {
ArrayList<String> rv = new ArrayList<String>();
open();
Cursor c = db.rawQuery("select * from reviews where IDRE="+id, null);
if(c==null)
return null;
c.moveToFirst();
rv.add(String.valueOf(c.getInt(c.getColumnIndex("IDRE"))));
rv.add(String.valueOf(c.getInt(c.getColumnIndex("ID_FK"))));
rv.add(c.getString(c.getColumnIndex("DATE")));
rv.add(c.getString(c.getColumnIndex("TYPE")));
rv.add(String.valueOf(c.getInt(c.getColumnIndex("COST"))));
rv.add(c.getString(c.getColumnIndex("SERVICE")));
rv.add(c.getString(c.getColumnIndex("ATMOSPHERE")));
rv.add(c.getString(c.getColumnIndex("OVERALL")));
rv.add(c.getString(c.getColumnIndex("COMMENT")));
c.close();
close();
return rv;
}catch(Exception e) {
return null;
}
}
Second way:
public ArrayList<String> getList(int id) {
try {
ArrayList<String> rv = new ArrayList<String>();
open();
String[] columns=new String[]{"IDRE","ID_FK","DATE","TYPE","COST","SERVICE","ATMOSPHERE","OVERALL","COMMENT"};
Cursor c=sql_db.query("reviews", columns, "IDRE"+"=?", new String[] {String.valueOf(id)}, null, null, null);
if(c==null)
return null;
c.moveToFirst();
rv.add(String.valueOf(c.getInt(c.getColumnIndex("IDRE"))));
rv.add(String.valueOf(c.getInt(c.getColumnIndex("ID_FK"))));
rv.add(c.getString(c.getColumnIndex("DATE")));
rv.add(c.getString(c.getColumnIndex("TYPE")));
rv.add(String.valueOf(c.getInt(c.getColumnIndex("COST"))));
rv.add(c.getString(c.getColumnIndex("SERVICE")));
rv.add(c.getString(c.getColumnIndex("ATMOSPHERE")));
rv.add(c.getString(c.getColumnIndex("OVERALL")));
rv.add(c.getString(c.getColumnIndex("COMMENT")));
c.close();
close();
return rv;
}catch(Exception e) {
return null;
}
}

What's the best way to iterate an Android Cursor?

I frequently see code which involves iterating over the result of a database query, doing something with each row, and then moving on to the next row. Typical examples are as follows.
Cursor cursor = db.rawQuery(...);
cursor.moveToFirst();
while (cursor.isAfterLast() == false)
{
...
cursor.moveToNext();
}
Cursor cursor = db.rawQuery(...);
for (boolean hasItem = cursor.moveToFirst();
hasItem;
hasItem = cursor.moveToNext()) {
...
}
Cursor cursor = db.rawQuery(...);
if (cursor.moveToFirst()) {
do {
...
} while (cursor.moveToNext());
}
These all seem excessively long-winded to me, each with multiple calls to Cursor methods. Surely there must be a neater way?
The simplest way is this:
while (cursor.moveToNext()) {
...
}
The cursor starts before the first result row, so on the first iteration this moves to the first result if it exists. If the cursor is empty, or the last row has already been processed, then the loop exits neatly.
Of course, don't forget to close the cursor once you're done with it, preferably in a finally clause.
Cursor cursor = db.rawQuery(...);
try {
while (cursor.moveToNext()) {
...
}
} finally {
cursor.close();
}
If you target API 19+, you can use try-with-resources.
try (Cursor cursor = db.rawQuery(...)) {
while (cursor.moveToNext()) {
...
}
}
The best looking way I've found to go through a cursor is the following:
Cursor cursor;
... //fill the cursor here
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
// do what you need with the cursor here
}
Don't forget to close the cursor afterwards
EDIT: The given solution is great if you ever need to iterate a cursor that you are not responsible of. A good example would be, if you are taking a cursor as argument in a method, and you need to scan the cursor for a given value, without having to worry about the cursor's current position.
I'd just like to point out a third alternative which also works if the cursor is not at the start position:
if (cursor.moveToFirst()) {
do {
// do what you need with the cursor here
} while (cursor.moveToNext());
}
Below could be the better way:
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
//your code to implement
cursor.moveToNext();
}
}
cursor.close();
The above code would insure that it would go through entire iteration and won't escape first and last iteration.
How about using foreach loop:
Cursor cursor;
for (Cursor c : CursorUtils.iterate(cursor)) {
//c.doSth()
}
However my version of CursorUtils should be less ugly, but it automatically closes the cursor:
public class CursorUtils {
public static Iterable<Cursor> iterate(Cursor cursor) {
return new IterableWithObject<Cursor>(cursor) {
#Override
public Iterator<Cursor> iterator() {
return new IteratorWithObject<Cursor>(t) {
#Override
public boolean hasNext() {
t.moveToNext();
if (t.isAfterLast()) {
t.close();
return false;
}
return true;
}
#Override
public Cursor next() {
return t;
}
#Override
public void remove() {
throw new UnsupportedOperationException("CursorUtils : remove : ");
}
#Override
protected void onCreate() {
t.moveToPosition(-1);
}
};
}
};
}
private static abstract class IteratorWithObject<T> implements Iterator<T> {
protected T t;
public IteratorWithObject(T t) {
this.t = t;
this.onCreate();
}
protected abstract void onCreate();
}
private static abstract class IterableWithObject<T> implements Iterable<T> {
protected T t;
public IterableWithObject(T t) {
this.t = t;
}
}
}
import java.util.Iterator;
import android.database.Cursor;
public class IterableCursor implements Iterable<Cursor>, Iterator<Cursor> {
Cursor cursor;
int toVisit;
public IterableCursor(Cursor cursor) {
this.cursor = cursor;
toVisit = cursor.getCount();
}
public Iterator<Cursor> iterator() {
cursor.moveToPosition(-1);
return this;
}
public boolean hasNext() {
return toVisit>0;
}
public Cursor next() {
// if (!hasNext()) {
// throw new NoSuchElementException();
// }
cursor.moveToNext();
toVisit--;
return cursor;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Example code:
static void listAllPhones(Context context) {
Cursor phones = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
for (Cursor phone : new IterableCursor(phones)) {
String name = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.d("name=" + name + " phoneNumber=" + phoneNumber);
}
phones.close();
}
The Do/While solution is more elegant, but if you do use just the While solution posted above, without the moveToPosition(-1) you will miss the first element (at least on the Contact query).
I suggest:
if (cursor.getCount() > 0) {
cursor.moveToPosition(-1);
while (cursor.moveToNext()) {
<do stuff>
}
}
The cursor is the Interface that represents a 2-dimensional table of any database.
When you try to retrieve some data using SELECT statement, then the database will 1st create a CURSOR object and return its reference to you.
The pointer of this returned reference is pointing to the 0th location which is otherwise called as before the first location of the Cursor, so when you want to retrieve data from the cursor, you have to 1st move to the 1st record so we have to use moveToFirst
When you invoke moveToFirst() method on the Cursor, it takes the cursor pointer to the 1st location. Now you can access the data present in the 1st record
The best way to look :
Cursor cursor
for (cursor.moveToFirst();
!cursor.isAfterLast();
cursor.moveToNext()) {
.........
}
if (cursor.getCount() == 0)
return;
cursor.moveToFirst();
while (!cursor.isAfterLast())
{
// do something
cursor.moveToNext();
}
cursor.close();
Initially cursor is not on the first row show using moveToNext() you can iterate the cursor when record is not exist then it return false,unless it return true,
while (cursor.moveToNext()) {
...
}

Get all rows from SQLite

I have been trying to get all rows from the SQLite database. But I got only last row from the following codes.
FileChooser class:
public ArrayList<String> readFileFromSQLite() {
fileName = new ArrayList<String>();
fileSQLiteAdapter = new FileSQLiteAdapter(FileChooser.this);
fileSQLiteAdapter.openToRead();
cursor = fileSQLiteAdapter.queueAll();
if (cursor != null) {
if (cursor.moveToFirst()) {
do {
fileName.add(cursor.getString(cursor.getColumnIndex(FileSQLiteAdapter.KEY_CONTENT1)));
} while (cursor.moveToNext());
}
cursor.close();
}
fileSQLiteAdapter.close();
return fileName;
}
FileSQLiteAdapter class:
public Cursor queueAll() {
String[] columns = new String[] { KEY_ID, KEY_CONTENT1 };
Cursor cursor = sqLiteDatabase.query(MYDATABASE_TABLE, columns, null,
null, null, null, null);
return cursor;
}
Please tell me where is my incorrect. Appreciate.
try:
Cursor cursor = db.rawQuery("select * from table",null);
AND for List<String>:
if (cursor.moveToFirst()) {
while (!cursor.isAfterLast()) {
String name = cursor.getString(cursor.getColumnIndex(countyname));
list.add(name);
cursor.moveToNext();
}
}
Using Android's built in method
If you want every column and every row, then just pass in null for the SQLiteDatabase column and selection parameters.
Cursor cursor = db.query(TABLE_NAME, null, null, null, null, null, null, null);
More details
The other answers use rawQuery, but you can use Android's built in SQLiteDatabase. The documentation for query says that you can just pass in null to the selection parameter to get all the rows.
selection Passing null will return all rows for the given table.
And while you can also pass in null for the column parameter to get all of the columns (as in the one-liner above), it is better to only return the columns that you need. The documentation says
columns Passing null will return all columns, which is discouraged to prevent reading data from storage that isn't going to be used.
Example
SQLiteDatabase db = mHelper.getReadableDatabase();
String[] columns = {
MyDatabaseHelper.COLUMN_1,
MyDatabaseHelper.COLUMN_2,
MyDatabaseHelper.COLUMN_3};
String selection = null; // this will select all rows
Cursor cursor = db.query(MyDatabaseHelper.MY_TABLE, columns, selection,
null, null, null, null, null);
This is almost the same solution as the others, but I thought it might be good to look at different ways of achieving the same result and explain a little bit:
Probably you have the table name String variable initialized at the time you called the DBHandler so it would be something like;
private static final String MYDATABASE_TABLE = "anyTableName";
Then, wherever you are trying to retrieve all table rows;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from " + MYDATABASE_TABLE, null);
List<String> fileName = new ArrayList<>();
if (cursor.moveToFirst()){
fileName.add(cursor.getString(cursor.getColumnIndex(COLUMN_NAME)));
while(cursor.moveToNext()){
fileName.add(cursor.getString(cursor.getColumnIndex(COLUMN_NAME)));
}
}
cursor.close();
db.close();
Honestly, there are many ways about doing this,
I have been looking into the same problem! I think your problem is related to where you identify the variable that you use to populate the ArrayList that you return. If you define it inside the loop, then it will always reference the last row in the table in the database. In order to avoid this, you have to identify it outside the loop:
String name;
if (cursor.moveToFirst()) {
while (cursor.isAfterLast() == false) {
name = cursor.getString(cursor
.getColumnIndex(countyname));
list.add(name);
cursor.moveToNext();
}
}
Update queueAll() method as below:
public Cursor queueAll() {
String selectQuery = "SELECT * FROM " + MYDATABASE_TABLE;
Cursor cursor = sqLiteDatabase.rawQuery(selectQuery, null);
return cursor;
}
Update readFileFromSQLite() method as below:
public ArrayList<String> readFileFromSQLite() {
fileName = new ArrayList<String>();
fileSQLiteAdapter = new FileSQLiteAdapter(FileChooser.this);
fileSQLiteAdapter.openToRead();
cursor = fileSQLiteAdapter.queueAll();
if (cursor != null) {
if (cursor.moveToFirst()) {
do
{
String name = cursor.getString(cursor.getColumnIndex(FileSQLiteAdapter.KEY_CONTENT1));
fileName.add(name);
} while (cursor.moveToNext());
}
cursor.close();
}
fileSQLiteAdapter.close();
return fileName;
}
Cursor cursor = myDb.viewData();
if (cursor.moveToFirst()){
do {
String itemname=cursor.getString(cursor.getColumnIndex(myDb.col_2));
String price=cursor.getString(cursor.getColumnIndex(myDb.col_3));
String quantity=cursor.getString(cursor.getColumnIndex(myDb.col_4));
String table_no=cursor.getString(cursor.getColumnIndex(myDb.col_5));
}while (cursor.moveToNext());
}
cursor.requery();
public List<String> getAllData(String email)
{
db = this.getReadableDatabase();
String[] projection={email};
List<String> list=new ArrayList<>();
Cursor cursor = db.query(TABLE_USER, //Table to query
null, //columns to return
"user_email=?", //columns for the WHERE clause
projection, //The values for the WHERE clause
null, //group the rows
null, //filter by row groups
null);
// cursor.moveToFirst();
if (cursor.moveToFirst()) {
do {
list.add(cursor.getString(cursor.getColumnIndex("user_id")));
list.add(cursor.getString(cursor.getColumnIndex("user_name")));
list.add(cursor.getString(cursor.getColumnIndex("user_email")));
list.add(cursor.getString(cursor.getColumnIndex("user_password")));
// cursor.moveToNext();
} while (cursor.moveToNext());
}
return list;
}
a concise solution can be used for accessing the cursor rows.
while(cursor.isAfterLast)
{
cursor.getString(0)
cursor.getString(1)
}
These records can be manipulated with a loop

fetching data from sqlite into array in android

The code to returns all the data in the table in list.But this isn't working.
I've called this method from CheckData class which is called by main class
public List<String[]> selectAll() {
List<String[]> list = new ArrayList<String[]>();
Cursor cursor = db
.query(TABLE_NAME, null, null, null, null, null, null);
int x = 0;
if (cursor.moveToFirst()) {
do {
String[] b1 = new String[] { cursor.getString(1),
cursor.getString(2) };
list.add(b1);
x = x + 1;
} while (cursor.moveToNext());
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
cursor.close();
return list;
}
My database contains 3 columns - id(integer primary key), symbol(text) and company_name(text).
My Data Base name is AppDB and table name is scrip.
Here are the good tutorial to LEARN use of Android-SQLite.
so,I also advise you the same As I answered here

Categories

Resources