CursorWindowAllocationException in standard ORMLite method - android

I need save some objects in DB. I'm using this code in my Dao class.
public void saveActions(List<Action> actionList) throws SQLException {
for (Action action : actionList) {
createOrUpdate(action);
}
}
And sometimes I have CursorWindowAllocationException in createOrUpdate() function.
Does anyone have solution of this problem?

If you look up the source of CursorWindowAllocationException it reads:
This exception is thrown when a CursorWindow couldn't be allocated,
most probably due to memory not being available.
If you follow the stack, you'll see that the call com.j256.ormlite.android.AndroidDatabaseConnection.queryForLong is creating a cursor for every createOrUpdate call.
So what's likely happening here is that there are too many Cursors being created before the memory is freed.
You should execute these calls in a transaction, or better yet, use batch tasks. E.g.
actionDao.callBatchTasks(new Callable<Void>() {
public Void call() throws SQLException {
for (Action action : actionList) {
actionDao.createOrUpdate(action);
}
return null;
}
});

You must call cursor.close(); in finally { } block when you do not need cursor anymore. Cursor allocation will fail without calling close() on cursor after some time when system resources for cursor allocation will be not available.

Related

Closing database connection with SqlBright

I'm migrating the following pattern of accessing the Android app's SQLite database into the RxJava world:
public List<Stuff> doStuff(){
synchronized (lock) {
open(); // this effectively checks for isOpen() then calls getWritableDatabase()
// query the database for stuff
close(); // SQLiteOpenHelper close method
return stuffList;
}
}
Something I'm struggling is when should I close the database connection? I know there are patterns for not closing the connection at all as well as closing the connection as part of the Activity method. However, those patterns would require me applying the logic to the whole database manager class which I'd like to avoid if possible. Was hoping maybe there's a suggested way to handle this with RxJava and specifically SqlBright wrapper? My migrated code looks something like this:
public Observable<List<Stuff>> doStuff(){
synchronized (lock) {
open();
String sql = <..>;
return db.createQuery(tableName, sql, args).mapToList(mStuffMapper);
// where do I close()?
}
}
The solution I'm after, ideally, should allow me to change this one method, keeping the rest with the current open/close pattern.
You can use Subscription to close the connection.
db.createQuery(tableName, sql, args)
.mapToList(mStuffMapper);
.doOnSubscribe(new Action0() {
#Override public void call() {
close();
}
});
Subscription subscribe = doStuff().subscribe();
subscribe.unsubscribe();

FATAL EXCEPTION: ParseRequest.NETWORK_EXECUTOR-thread-60

I am getting this error in my Activity where I use Parse SDK. The whole code is here, but the code is huge and the crash is not even giving me the line of code where it is occuring. I searched a lot but found nothing about this error. Can anyone tell me what exactly this error means?
Screenshot:
Since adding a code example, I will write an answer.
You are using AsyncTask to do multiple queries and to know when these finish.
Parse recently added Bolts to their API (1.7.0 or 1.7.1) https://github.com/BoltsFramework/Bolts-Android
With Bolts you can do the same as you can with Promises in javascript, in case you are familiar with that.
A simple example deleting all objects matching a query:
findAsync(query).continueWithTask(new Continuation<List<ParseObject>, Task<Void>>() {
public Task<Void> then(Task<List<ParseObject>> results) throws Exception {
// Collect one task for each delete into an array.
ArrayList<Task<Void>> tasks = new ArrayList<Task<Void>>();
for (ParseObject result : results) {
// Start this delete immediately and add its task to the list.
tasks.add(deleteAsync(result));
}
// Return a new task that will be marked as completed when all of the deletes are
// finished.
return Task.whenAll(tasks);
}
}).onSuccess(new Continuation<Void, Void>() {
public Void then(Task<Void> ignored) throws Exception {
// Every comment was deleted.
return null;
}
});
The return Task.whenAll(tasks); returns a task that fires onSuccess only when all the tasks in the tasks arraylist has completed.
Not only does this rely on ParseĀ“ own background management, this example also makes all the tasks run in parallel, so is generally faster.
In your situation, you would simple need to create an ordinary method that:
Use the new built-in functions to return a task for both query1 and query2
Add those to an arraylist of tasks
return Task.whenAll(tasks)
Lets say this method is loadPicsInBg, then to use it:
loadPicsInBg().onSuccess(new Continuation<Void, Void>() {
public Void then(Task<Void> ignored) throws Exception {
// all the queries completed
return null;
}
});
I know this is a huge refactor and maybe you can do fine with the simpler callback approach, but Bolt indeed gives more power over the complex queries if used correctly. Furthermore it avoids the problem with nested queries creating a ever increasing indentation in the code making it difficult to read.

Unable to getWritableDatabase() - sometimes

I regularly get reports from users with this error.
Unable to getWritableDatabase.
try {
//dbOpenHelper is a standard SQLiteOpenHelper
dbOpenHelper.getWritableDatabase();
} catch (Exception e) {
//unable to connect to database.
return;
}
This is only happening sometimes. What could it be? Any fixes or workarounds?
There isn't much to go off of, need to see your LogCat to help any further. Are you closing your dbOpenHelper?
Here is a quick example:
public DatabaseControl open() throws SQLiteException {
dbHelper = new DatabaseHelper(context);
database = dbHelper.getWritableDatabase();
return this;
}
public void close() {
dbHelper.close();
}
Edit 1 - Again, this is my best guess since a LogCat is unobtainable. (In the end it might be in your best interest to run this application on your Dev device and try to replicate and then get your full LogCat ouput)
It sounds to me like the Activity that has the DB is being accessed and processed fine with a proper close(), but in some instances maybe instead of running through that Activity the user presses the back button where onBackPressed() maybe should have a DB close() call?
In other words, to troubleshoot, I would #Override Acitivity lifecycle methods: onPause(), onResume(), onStart(), onStop(), and onDestroy() as well as onBackPressed() simply adding the DB close() and test your application then. If you do this then, I would think that, any returning lifecycle, such as onStart() or onResume() should contain the DB getWritableDatabase()
According to the documentation (see below), there really is no way to get Unable to getWritableDatabase unless the database was not closed properly. Also make sure that if you change anything in your SQlite code / structure that you need to update the DB Version #.
public SQLiteDatabase getWritableDatabase ()
Create and/or open a database that will be used for reading and writing. The first time this is called, the database will be opened and onCreate(SQLiteDatabase), onUpgrade(SQLiteDatabase, int, int) and/or onOpen(SQLiteDatabase) will be called.
Once opened successfully, the database is cached, so you can call this method every time you need to write to the database. (Make sure to call close() when you no longer need the database.) Errors such as bad permissions or a full disk may cause this method to fail, but future attempts may succeed if the problem is fixed.
Edit 2
I should have shown how I called on the open() and close() methods the first time. Sorry about that. You don't need the DatabaseHelper open unless you are retrieving or posting to it, so immediately after processing close it until the next time you need it. Same goes for the Cursor, etc
Below is how I query the database, I open everything, retrieve the information, process the information and then immediately close everything. See below:
DatabaseControl control = new DatabaseControl(this);
try {
database = (new DatabaseHelper(this)).getWritableDatabase();
DatabaseControl control = new DatabaseControl(DbTestDisplay.this);
control.open();
control.fetchAllItems();
Cursor c = database.query(GlobalDBVars.TABLE_NAME, null, null, null, null, null, null, null);
c.moveToFirst();
int initialCount = c.getCount();
Log.i("cursor", "Initial Count = " + initialCount);
List<Integer> x = new ArrayList<Integer>();
if (initialCount > 0) {
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
/* Process everything here */
} /* End for loop */
} /* End if statement */
control.close();
c.close();
database.close();
} catch (SQLException sqe) {
Log.e("fetchAllItems", "FAILED: " + sqe.getMessage() + " allData = ");
}
Try getReadableDatabase() instead of getWritableDatabase()
try {
//dbOpenHelper is a standard SQLiteOpenHelper
dbOpenHelper.getReadableDatabase();
} catch (Exception e) {
//unable to connect to database.
return;
}

Cancelling ORMLite Write in Background Thread Safely

I'm designing out a module in Android that does some processing and then writes to the database using ORMLite transactions. In particular, my background code will be something like:
public class BackgroundOperation implements Runnable {
#Override
public void run() {
//Do some stuff
//Write to the database in a transaction
try {
ORMHelper h = ORMHelper.getDefaultOrmHelper();
final MyModel modelObj = h.myModelDao.queryForId(someId);
TransactionManager.callInTransaction(
h.getConnectionSource(),
new Callable<Void>() {
public Void call() throws Exception {
modelObj.col1 = 10;
modelObj.col2 = "hello";
h.myModel2Dao.update(modelObj);
h.myModel2Dao.create(new MyModel2("a", "b"));
return null;
}
}
);
}
catch (Exception e) {
return null;
}
}
}
This runnable will then be executed by being submitted to a ThreadPoolExecutor. I want to be able to cancel the background thread if needed and am trying to make sure that if the operation is cancelled, then the transaction will simply fail and do nothing. For example, if I do this:
Future f = myThreadPoolExecutor.submit(new BackgroundOperation());
//Some time later
f.cancel(true);
Can I be sure that it will be an all or nothing deal with the transaction in ORMLite. That is, there is no cleanup needed and my modelObj will have either both col1 and col2 set or neither set? Do I have to do anything special when catching the InterruptedException in the Runnable to handle the case when a task is cancelled in this way, or can I simply exit?
If you call f.cancel(true), all that does is interrupt the Thread which causes wait(), sleep(), and some other methods to throw InterruptedException. It will not cancel the database transaction underway.
If you want, you can check for the interrupted bit in the middle of your IO operations:
h.myModel2Dao.update(modelObj);
if (Thread.currentThread().isInterrupted()) {
throw new RuntimeException("Thread was interrupted");
}
h.myModel2Dao.create(new MyModel2("a", "b"));
For more information about what happens when a thread is interrupted see here:
What does java.lang.Thread.interrupt() do?
Transactions are for when you are updating multiple objects as a single unit or writing to multiple tables. See the documentation about transactions which has an example of updating an Account and an Order inside of a transaction.
Also, you do not need to use a transaction if you are updating multiple fields in the same row. The update statement is considered to be a single unit and the database should ensure that the row gets updated atomically. Only if you are updating multiple different rows either in the same table or in separate tables do you need a transaction.
ORMLite will utilize the sqlite transactions under the covers. This is most likely a double phase commit which only allows you to commit a transaction as an entire unit.
In short, you can be assured that col1 and col2 will only be modified as a single atomic unit. Also, it if is interrupted the commit will fail and the changes to col1 and col2 will be rolled back.

Rethrowing an exception in Android

I'm developing an Android 2.2 application.
I want to catch and re throw the same exception. I want to do this because I have to close a cursor before exit the method (a finally statement, isn't it?)
Can I do that? How?
Thanks
If this is just to close the cursor correctly, you can do a try...finally without a catch. That would be something like that :
Cursor cursor = null;
try {
// initialize and do things with the cursor
} finally {
if (cursor != null) {
cursor.close();
}
}
Alternatively, if you're in an activity, you can use startManagingQuery; which will take care of your cursor lifecycle depending on the activity lifecycle.
Without discussing if this is a good practice you can do this:
throw new YourException();

Categories

Resources