0

I've got Fragments, where I cache data in every Fragment. I cache the data in an AsyncTask by downloading it in the doInBackground method from a server and save it in the onPostExecute to my database. So I always open the database connection in the onPostExecution. If I scroll "fast" threw the fragments, I think the AsyncTasks are pass the previews instances and there will be a android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:224) in the row, where I open the connection (getting dbHelper.getWritableDatabase())

I think there are two ways to solve this:

  • the onPostExecution method have to wait until the previews AsyncTask (onPostExecution) is finish

  • there's a way to use the same database connection for all instances of the AsyncTask, without locking them eachother

Is this correct? Somebody an idea, how to do this?

2 Answers 2

6

I would recommend you to use Loader instead of an AsyncTask to load your data in the background. Otherwise you have to manage cursors, synchronize correctly with the UI thread, and ensure all queries occured on a background thread. Besides, making use of the now deprecated startManagingCursor and managedQuery methods are extremely discouraged; they slow down your app, and can bring it to a screeching halt.

Android 3.0 introduced the Loader and LoaderManager classes to help simplify the process. Both classes are available for use in the Android Support Library, which supports all Android platforms back to Android 1.6.

Loaders ensure that all cursor operations are done asynchronously, thus eliminating the possibility of blocking the UI thread. Further, when managed by the LoaderManager, Loaders retain their existing cursor data across the activity instance (for example, when it is restarted due to a screen rotation), thus saving the cursor from unnecessary, potentially expensive re-queries. As an added bonus, Loaders are intelligent enough to monitor the underlying data source for updates, re-querying automatically when the data is changed.

Take a look to this blog to have more information about loaders http://www.androiddesignpatterns.com/2012/07/understanding-loadermanager.html

or visit the official documentation for android developers: http://developer.android.com/guide/components/loaders.html

Sign up to request clarification or add additional context in comments.

2 Comments

oh yeah, it's very difficult for me!! I think I have to have a ContentProvider between Loader and Database, right? Could it be, that Loaders are only to use for caching data from the UI? I want to cache some data from URLs and don't understand how I could get a ContentProvider, download and cache data here. Maybe the CursorLoader is to use for UI data and I could use the AsyncTaskLoader (instead of my AsyncTask)?
Well yes, the ContentProvider is in the middle as a wrapper of the actual sqlite database. But The contentProvider won't download data for you. For that you may want to write a service.
2

I think all the information you are looking for can be found on this post:

What are the best practices for SQLite on Android?

As for your use of the onPostExecution to save the data on the db, since the SQLiteDatabase class is thread safe, your application will be faster (and still safe) if you do it in the doInBackground method.

Keep in mind that if saving your data is made of multiple sql queries, it is easy to assure they are executed atomically (without the interference of other threads) by using transactions:

SQLiteDatabase's beginTransaction() at the Android developers website

which btw should be used anyway (inserting 1000 lines in a single transaction speeds things considerably up)

Hope this helps

2 Comments

thank you for your help! Don't know why, but I ever thought you can only access to file system in the main thread, where the onPostExecute, not the doInBackground is running. I was surprised positive to see, that it works here too! I surrounded all my sql queries with transactions now. Never closing the cursor (which is recommendet by the link in the post you refer to, Single SQLite connection ) solved the locking problem on the one hand, but it seems to be a dirty trick on the other hand. Or I'm wrong?
What do you mean with "never closing the cursor"? AFAIK cursors must be closed, otherwise Android will complain (often very loudly, especially on 2.2), or even throw an exception. Did you perhaps mean "never closing the SQLiteDatabase"? If so, it's ok: In my application I use a Database singleton saved in the application and it works fine (in fact I moved to this approach after some bad experiences with multiple database instances). Hope it helps

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.