Android cursor method gives error when i close the database - android

In Android I query some data from the database into a cursor,after it I close the database. After it when use cursor method it gives error. Anyone can explain why?

This is not really a direct answer, but it is an example of how to do what you are talking about. I have a class called ContactDataSource that allows access and manipulation of my database via a Cursor. To do this, the database needs to be able to be opened and closed. This is handled in my class via the following methods
public void open() throws SQLException{
db = helper.getWritableDatabase();
}
public void close(){
helper.close();
}
I need to be able to get all of my contacts, so that I can utilize their variables, modify them, etc. It would be inefficient, not to mention not very secure, to keep my database connection open the whole time I need the variables in question. I need to store the information from my database somewhere, somehow, on my device. In order to do that I need to call the following method
private String[] allColumns = {ContactDataSQLHelper.COLUMN_ID, ContactDataSQLHelper.COLUMN_CONTACT_NAME,
ContactDataSQLHelper.COLUMN_CONTACT_ADDRESS, ContactDataSQLHelper.COLUMN_CONTACT_NUMBER};
...
public ArrayList<ContactObject> getAllContacts(){
ArrayList<ContactObject> contacts = new ArrayList<ContactObject>();
// Again, without our Cursor, we can't actually point at any of the data we want to
// work with/manipulate
Cursor cursor = db.query(ContactDataSQLHelper.TABLE_CONTACTS, allColumns,
null, null, null, null, null);
cursor.moveToFirst();
while(!cursor.isAfterLast()){
ContactObject contact = cursorToContact(cursor);
contacts.add(contact);
cursor.moveToNext();
}
cursor.close();
return contacts;
}
which will return my list of contacts in the form of ContactObjects. You can see that this method will close our cursor's database connection once it is done. However, before it is closed, it calls cursorToContact(cursor) which will allow us to use our cursor to create a readable ContactObject
private ContactObject cursorToContact(Cursor cursor){
int id = cursor.getInt(0);
String name = cursor.getString(1);
String address = cursor.getString(2);
String number = cursor.getString(3);
return new ContactObject(name, address, number, id);
}
So in short: Open Connection -> Get what you need from your database -> Store it in an object/variable -> Close connection is the process that needs to be taken.
This can be achieved by call open method -> call getter method -> (if needed) call helper method -> call close method
It is important to note that if you want to reverse the process (save the modified database information) a similar process is followed, just using database setter methods instead of getter methods.

This is expected behavior. Cursors require the database to be open in order to be able to read their data.

Related

Android - Efficient way using the Database Cursor

I've implemented a sqlite database in my application and I'm using the Android Cursor. I've written a database class with e.g. the database name and the table and column names. Here I also have various methods, like the following:
public Cursor getCorrectQuestions(int topic) {
SQLiteDatabase db = getReadableDatabase();
Cursor questionCursor = db.rawQuery(
"Select * FROM Result, Question WHERE Result.qid = Question._id AND correct = 1 AND topic = " + topic,
null);
questionCursor.moveToFirst();
return questionCursor;
}
public Cursor getExamQuestions() {
SQLiteDatabase db = getReadableDatabase();
Cursor questionCursor = db.rawQuery("Select * FROM Question WHERE topic = 7", null);
questionCursor.moveToFirst();
return questionCursor;
}
public Cursor getAnswerItems(String id) {
SQLiteDatabase db = getReadableDatabase();
Cursor answerCursor = db.rawQuery(
"Select * FROM Answer, Question WHERE Question._id = " + id + " AND Question._id = Answer.qid", null);
answerCursor.moveToFirst();
return answerCursor;
}
public Cursor getUserResults(String qid) {
SQLiteDatabase db = getReadableDatabase();
Cursor userResultsCursor = db.rawQuery("SELECT result FROM Result, Answer WHERE Result.qid = " + qid, null);
userResultsCursor.moveToFirst();
return userResultsCursor;
}
In the QuizActivity which has 3 cursors (answerCursor, questionCursor, userResultCursor) I call these methods.
My question is: is it necessary to create a SQLiteDatabase Object in every method or is it possible to define this once in my database constructor? And do I need 3 different cursors in my activity or is there a better way to handle this?
Assuming the methods you have written are part of a SQLiteOpenHelper, you are not really creating 3 database objects. Only the first call to getReadableDatabase() actually creates a database object, and subsequent calls reuse the same object over again.
You also need to make a new Cursor for each query you perform, as they cannot be edited after creation. In this sense, there is no way to simplify what you have already done.
As far as improvements to your code, there are a few things you can look at:
Consider putting your database in a ContentProvider and accessing it via URI's. This will require more upfront work, but will make it much easier if you want to share your database with other apps or sync your data to a server in the future.
Leave the cursor in its default position (don't call moveToFirst()). That way when the caller receives the cursor, it can use the following code to start iterating cursor rows without performing any further checks:
while (cursor.moveToNext()) {
// extract data
}
This is because the cursor returned from a query is initially positioned before the first row of data, so if the cursor is empty then the code inside the while loop simply never executes at all.

sqlite android create unique column that no need to check availability when have to store

I developing news app that store all of news in sqlite database.
It will be a big database during time.
When i get data from API, check database to have every news and if doesn't exist store them to it. it takes 3-10 sec on every time when app run by user ( will take more during days ).
Is there anyway to store my data to database in an asynctask that doesn't freeze my app ? or another efficient way ?
every news has unique id. can i change my id column to unique that i don't have to check every time and store directly to database and database don't save it when it's available ?
for (int i = 0; i < jsonArrayAll.length(); i++)
if (!db.isNewsExist(news.getNews_id()))
db.addNews(news);
public boolean isNewsExist(String news_id) {
boolean exist;
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor =
db.query("news", COLUMNS_NEWS, " news_id = ?",
new String[]{news_id}, // d. selections args
null, // e. group by
null, // f. having
null, // g. order by
null); // h. limit
if (!cursor.moveToFirst()) {
return false;
}
exist = cursor.getString(1) != null;
cursor.close();
db.close();
return exist;
}
Yes- just put the update code in the doInBackground of an AsyncTask. SQLite can handle being called from multiple threads. As for improvements- don't query and then add. Just try to insert- if the column has a unique constraint that's violated it will throw an exception you can catch and ignore.

Android create second database after first database is created

So I created first database, and now I need to create separate database, zipped it and send it to server.
I'm just wondering if it is doable?
And how can I do it?
Here's the basic logic of what you want to do, it'll have to be supplemented with specific code from here: https://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html
and here: https://developer.android.com/reference/android/database/Cursor.html
and here: https://developer.android.com/reference/android/content/ContentValues.html
SQLiteDatabase database1 = SQLiteDatabase.openDatabase(<PATH TO DATABASE1>, null, 0);
SQLiteDatabase database2 = SQLiteDatabase.openOrCreateDatabase(<WHEREVER YOU WANT DATABASE2 TO GO>, null);
Cursor cursor = database1.query(<You'll really just have to fill this in with what you're pulling from database1, it's way too specific>);
ContentValues contentValues;
while (cursor.moveToNext()) {
contentValues = new ContentValues();
contentValues.put(<Column key>, <Column value from cursor>)
// I.E. contentValues.put(ID_KEY, cursor.getString(cursor.getColumnIndex(ID_KEY));
// <INSERT THE REST OF YOUR COLUMNS INTO contentValues>
database2.insert(<TABLE_NAME>, null, contentValues);
}
cursor.close();
database1.close();
database2.close();
To send it, that depends on way too many things for me to address. You have the database file now, send it using whatever protocol you please. If you don't know how to do this, search for "Android send File to Server" (try with an without quotes).

Quering SqlLite database where clause Android

Hi I am developing an android app.I am trying to query from the database. I need to fetch everything from the table TASK where dbDate = AlarmDate and dbdTime = AlarmTime.
c = db.rawQuery("SELECT * FROM TASK WHERE dbDate = '"+AlarmDate+"' AND dbTime= '"+Alarmtime+"'", null);
The problem is ,the cursor c is null.
I am not sure where I am going wrong in the query. Please Help.
Thanks!
Android has binding method to avoid sql inject. You can use the second parameter to provide the variables of SQL.
Cursor cur = db.rawQuery("SELECT * FROM TASK WHERE dbDate = ? AND dbTime = ? ", new String[]{AlarmDate, AlarmDate});
Going by your comment 'I have used db = openOrCreateDatabase("Globus", 0, null); where Globus is the db name', you are not using SQLite properly with android.
What you should be doing is creating class which extends SQLiteOpenHelper, then make sure you override the onCreate and onUpgrade methods, these are the methods where you create tables and make changes, it has been said a hundred times on here so I will provide a link to a tutorial: http://www.codeproject.com/Articles/119293/Using-SQLite-Database-with-Android
When you do database operations, on the class call getWritableDatabase (http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getWritableDatabase())
I say call getWritableDatabase because that way you don't need to worry if you can write to it, a writable database is also readable. Just FYI. Ask away for more details.
This should be the process of reading (writing is the same, just use what method you want instead of query):
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.beginTransaction();//this should lock the tables you are reading
Cursor c = db.rawQuery("select 1 where 1=?", new String[]{"1"});
if(c.moveToFirst()){
do{
//Do what you want with the row
}while(c.moveToNext());
}
c.close();
db.setTransactionSuccessful();
db.endTransaction();
db.close();
Here is the source code of a database helper I wrote, maybe it will help, read through it, understand how it works. https://bitbucket.org/FabianCCook/dbhelper/src/af7a8eba8d1a3f139e4170bbef9f1a2d3fdf1b47/src/nz/smartlemon/DatabaseHelper/ApplicationDataDbHelper.java?at=master
And if you want to know the reason the open methods exist read through this code
(This class was made from the help of someone elses code)
https://bitbucket.org/FabianCCook/dbhelper/src/af7a8eba8d1a3f139e4170bbef9f1a2d3fdf1b47/src/nz/smartlemon/DatabaseHelper/SDCardSQLiteOpenHelper.java?at=master
SQLiteDatabase db = getReadableDatabase();
Cursor cur = db.rawQuery("SELECT * FROM TASK WHERE dbDate = '"+AlarmDate+"' AND dbTime = '"+AlarmTime+"'",new String [] {});
Make sure you have gotten a readable database for 'db' or it will return null everytime.
Also change the end of your raw query to new String [] {}
Hope this helps, this is what I use in my applications.

Is this bad database coding?

In my DatabaseHelper class that extends SQLiteOpenHelper I've set various methods to return Cursors to my other Activities so that I don't perform any queries within any other class except DatabaseHelper. In those methods I don't close the Cursor or database afterwards, and I return it like:
public Cursor getCoursesLeft()
{
// Open a readable database.
SQLiteDatabase database = this.getReadableDatabase();
// Query the database and return the cursor.
return database.query(DEGREE_PLAN_TABLE, null, DEGREE_COLUMN_TAKEN + " = ?",
new String[] { "0" }, null, null, DEGREE_COLUMN_CLASS_NAME + " COLLATE NOCASE");
}
From whichever Activity I call the method from, I do ensure to close the Cursor that's returned after I use it.
Since Cursor is an Object, it should pass by reference, correct? So closing it from the other Activity should close the original object, and if I understand it correctly closing the Cursor also closes the database.
Is this a bad coding practice?
It seems like randomly I'll get a LogCat error saying close was never called on the database and the only thing I can find in my code that might be the reason is how I return the Cursors in those methods.
and if I understand it correctly closing the Cursor also closes the
database.
That does not sound quite right. You have to explicitly close the database after you've closed all cursors. The logcat errors are due to you not closing the databse and probably attempting to open another instance of it.
The order is important, cursors first, then the DB instance.
<bad joke in 3.. 2.. 1...>
The rest does not sound like any bad practice, when you gotta db it you just gotta db it. :D
[EDIT]: You said you've done this:
public Cursor getCoursesLeft()
{
// Open a readable database.
SQLiteDatabase database = this.getReadableDatabase();
^^^ here you're creating a new instance of the db
which means the db is opened for reading, and the scope of this variable
is lost outside this function. This means you can not close this instance explicitly
// Query the database and return the cursor.
return database.query(DEGREE_PLAN_TABLE, null, DEGREE_COLUMN_TAKEN + " = ?",
new String[] { "0" }, null, null, DEGREE_COLUMN_CLASS_NAME + " COLLATE NOCASE");
}
Instead have a database variable that you can access outside this method and close it once you're done working with the Cursor (and you've closed the cursor)
SQLiteDatabase database;
public Cursor getCoursesLeft()
{
// Open a readable database.
database = this.getReadableDatabase();
// Query the database and return the cursor.
return database.query(DEGREE_PLAN_TABLE, null, DEGREE_COLUMN_TAKEN + " = ?",
new String[] { "0" }, null, null, DEGREE_COLUMN_CLASS_NAME + " COLLATE NOCASE");
}
public void someOtherFunction() {
Cursor blah = getCoursesLeft();
// do something with blah
blah.close();
database.close();
}
Not closing a cursor just causes memory leaks. Closing a database is different.
Closing a cursor is like closing a particular connection to certain .file files generated when the cursor is created.
Hence you should ALWAYS close your cursor.
Is this bad coding?
No, and yea. Don't let your Activity mess around with those temp files. While nothing will happen it just doesn't seem nice

Categories

Resources