When accessing a database within an AsyncTask, should the database connection be a member of the parent Activity or opened/closed within each AsyncTask?
If the connection is a member of the activity, I'm concerned that when switching between my application's activities there is the possibility that the database connection could be closed before the AsyncTask utilizing it has completed.
Not something I've ever really thought about but instinctively I'd make the AsyncTask as self-contained as possible, i.e., have it handle its own db operations internally. The same applies to any threaded code.
EDIT: Here's a link to a good article discussing multiple access to SQLite in Android...Android SQLite Locking
Related
I'm trying to set up Room as a way to simplify access to SQLite database. I've written some code, but I can't run it, as app throws following exception:
Cannot access database on the main thread since it may potentially lock the UI for a long period of time
I've done some research and what I've found is .allowMainThreadQueries() in databaseBuilder which seems to me like terrible solution, because it's like muting error message, not fixing real cause.
So, what are best practices? When (in app lifecycle) should I create my database and where should I store it so I could access it from any Activity I want?
When (in app lifecycle) should I create my database
Lazy-create your RoomDatabase on first access, just as you would when using SQLiteOpenHelper directly.
where should I store it
A singleton will be a typical pattern, just as you would when using SQLiteOpenHelper directly.
Neither of those questions have anything to do with the error message. That is a matter of accessing the database on a background thread, just as you would when using SQLiteOpenHelper directly. For #Query methods, you have the option of having the method return a LiveData or an RxJava type (e.g., Flowable), in which case Room will take care of doing the work on a background thread. For other operations (e.g., #Insert), you are responsible for invoking those methods on a background thread yourself (Thread, AsyncTask, ThreadPoolExecutor, IntentService, JobIntentService, etc.).
Is it OK to have SQLite interactions on UI thread ??
Is it a best practice to embed interactions with SQLite within a service(AsyncTask or IntentService) or should we use CursorLoader for SQLite??
1)If I use IntentService to return a list of user defined objects then how do I that. Should we use BroadcastReciever and put the list of objects in intent as ArrayList of Parcelable objects and send it back to UI thread.
2)If I have to use cursor Loaders then I need to write custom loader for SQLite by extending AsyncTaskLoader and override doInBackGround method where I add required code.
Please suggest me which is better approach as I am new to android and also share the code if anybody has it
It is perfectly fine to use SQLite on the UI Thread. There is no need to add all that service and parable stuff, except perhaps if you intend to scroll through huge amounts of data.
Although you can access database on UI thread & update views straightaway.
One should avoid this practice & do database access on helper threads i.e. use asynctasks/services with worker threads even if operation is taking less than 5 seconds. You can always use non-UI to UI thread communication mechanisms in android for updating views once thread is done with it's job.
Refer this link to learn basics about non-UI to UI thread communication mechanisms. http://www.intertech.com/Blog/android-non-ui-to-ui-thread-communications-part-1-of-5/
I normally use AsyncTasks created on activity/service for DB access.
If android later decides to disallow DB access on UI thread, then your code will not need rework if DB access already on non-UI thread.
There is history with android that network access was earlier allowed on UI thread, but now if you set targetSDKversion=11, then application will throw NetworkOnMainThreadException & exit.
Hence, it is better to DB access on non-UI thread.
I saw some articles about CursorLoader like this, but I still don't understand the particular purpose of using it.
I developed apps with SQL and cursor retrieving. The point is it was very fast. I queried and parsed cursor with >500 record and 8 columns by a few millisecond. So didn't notice any delay event on old phones. So why do I need to use it?
A CursorLoader is used ostensibly to query a ContentProvider with LoaderManager.LoaderCallbacks<Cursor>.
There are two things that you need to keep in mind for understanding the CursorLoader:
It loads data on a separate thread.
It monitors the underlying data source for updates, re-querying when changes are detected.
Now coming to the LoaderManager. Simply stated, the LoaderManager is responsible for managing one or more Loaders associated with an Activity or Fragment. Each Activity and each Fragment has exactly one LoaderManager instance that is in charge of starting, stopping, retaining, restarting, and destroying its Loaders. These events are sometimes initiated directly by the client, by calling initLoader(), restartLoader(), or destroyLoader(). Just as often, however, these events are triggered by major Activity/Fragment lifecycle events. For example, when an Activity is destroyed, the Activity instructs its LoaderManager to destroy and close its Loaders (as well as any resources associated with them, such as a Cursor).
The LoaderManager does not know how data is loaded, nor does it need to. Rather, the LoaderManager instructs its Loaders when to start/stop/reset their load, retaining their state across configuration changes and providing a simple interface for delivering results back to the client.
So you see, all this is not easily possible when you use a simple AsyncTask and query an SQLite database. This is why the framework provides CursorLoader and LoaderManager:
To perform queries on a separate thread.
To monitor the data source for changes and update the UI.
To integrate easily with the life cycle of Activity and Fragment.
The practical purpose is simply how Android handles UI elements (that is on the main thread). Basically, anything that may be a long running process, run it in a background thread so you don't lockup the main thread. This can't be said enough. After Gingerbread this has been more enforced by Android itself. Check out SQL helper. To get to the point in regards to opening an SQLite connection and its "speed":
Because they can be long-running, be sure that you call getWritableDatabase() or getReadableDatabase() in a background thread, such as with AsyncTask or IntentService.
By using CursorLoader, it makes your life easier if you need ContentResolver and are using SQLite DB. More importantly, it runs on the background. Just because you've never seen the DB lock up doesn't mean it doesn't happen. Better safe than sorry, and the main thread will thank you :)
Use the CursorLoader from Support Library to run asynchronous queries in the background. In this way, you ensure that data loading does not cause “Application Not Responding” messages.
A CursorLoader runs a asynchronous query in the background against a ContentProvider and then it returns the result back to the Activity or the Fragment from where it is called.
The main advantage is that it helps the user to interact with Activity or Fragment while the query is still running in the background.
world!
I'm building an application that has to retrieve data from a server in several different Activitys. Some data is cached to a SQLite database (and retrieved from there instead in future), and some must be called fresh from the server every time. I need to know what the best multi-threaded architecture would be for this application. Multiple Activitys will be connecting to the server.
I'm thinking a bound Service would be best, but of course I'm not sure. If that's the way to go, how exactly do I implement multi-threading in it?
Thanks
The android classes such as IntentService and AsynTask are thread safest because they will not keep your activity open when your activity's finish method is called. If you create your own Thread implementation you must remember to stop the thread on Activity finish so that the process' memory will be reclaimed.
In a situation like yours I am going with a set of singleton factory classes to access local SQLite db and a background service doing asynchronous replication
I have a SQLite Database in android that is accessed from a thread when the activity is running, and in the onPause() of the activity a new thread is created to save everything into the database with a different thread to avoid timeout issues. However, when I try to do so, I either get database is locked errors. How can I fix this? Since I need to access the database from a separate thread in onPause(), could I delete somehow my previous access to it since I wouldn't use it again?
You cannot access an SQLite database when it already has a lock on it.
To avoid this, Android gives you ContentProviders to handle this sort of thing.
You should implement your own ContentProvider to do this kind of thing.
That said, databases can NEVER be assumed to be threadsafe unless you manage the threads yourself. Avoid using the db like this. Instead, cache the data (on a stack, perhaps) and request access to the database with a callback when your current transaction is complete.
As far as I know SQLite does not support concurrent access, so you either have to have a dedicated thread to provide access, or you have to obtain a lock to the SQLite object instance.