The documentation for Android's SQLite interfaces mention that database accesses should be performed from an IntentService as they are potentially long-running operations, so the GUI thread should not block on them.
The IntentService is shut down as soon as no further Intents are queued for it, which would happen basically after every request, so the database handles are built up and destroyed for each query as well, which seems wasteful.
Is there a way to keep an IntentService around longer, or somehow otherwise avoid a race between the GUI thread posting more Intents and the service answering them?
Should I just make my query Intents contain a list of queries that should all be performed, or would that cause other problems with message sizes?
The documentation for Android's SQLite interfaces mention that database accesses should be performed from an IntentService as they are potentially long-running operations, so the GUI thread should not block on them.
I/O of all forms should be performed on background threads, so as not to block the main application thread. IntentService itself is not a great choice, given changes on Android 8.0+.
A more typical approach nowadays is to have database access be managed by a singleton repository (whether a manually-created singleton or a singleton supplied to you via a dependency injection framework). The repository can use any number of approaches to provide a reactive API while doing the I/O on a background thread, including:
RxJava
LiveData and ordinary threads, executors, etc.
Kotlin coroutines
If you use Room as your database access layer, it gives you all three of those options "for free". Some other ORMs offer similar capabilities.
Is there a way to keep an IntentService around longer, or somehow otherwise avoid a race between the GUI thread posting more Intents and the service answering them?
Background services can only run for one minute. If your concern is the overhead in opening the database, use a singleton repository, and only open it once per process invocation. It's also entirely possible that you do not need a service; if you have a foreground UI, a service may be pointless.
Should I just make my query Intents contain a list of queries that should all be performed...?
Um, possibly, but again, using a service here may not be necessary and definitely makes the problem more complex.
So: use a background thread for I/O. That does not have to involve a service.
Related
As I understood, Firebase Database performs all the reading tasks on a single thread.
Is there a way to split that work into few different threads?
Is there a way to make a tasks execute before another? some parallel to handler.postAtFrontOfQueue() ?
The Firebase client handles all network and disk I/O on a separate thread to avoid interfering with the UI of your Android app. The callbacks into your code are invoked on the main thread, so that your code can interact with the UI.
The operations are executed in the same order in which you call their APIs. There is no way to re-order operations. There is also no way to set up multiple threads, nor have I ever seen a need for that. Interacting with a remote service is inherently an I/O intensive operations, which is not helped by multi-threading.
This sounds like a XY problem. If you describe the actual problem that you're trying to solve, we may be able to help better.
In my Android app, I have a local DB (SQLite) that the app needs to query for data. The query may take a long time (>5 seconds) so I am avoiding using the main UI thread for that. The returned data may also be rather large (> 1 MB).
Between AsyncTasks, Threads, ExecutorService, and IntentService, (and maybe more) what's the best class/API to use in Android to do this? Are they all more or less the same in terms of what they offer? Or is there a clear winner and a better suited class for database access?
The answer, I'm sure you can predict, is "it depends".
If you are writing a set of related calls (for example that will sync your database using an API), then I would want to use an IntentService since it's a long running operation not directly tied to your user interface.
If it's a one-time operation hitting the database to get a result set, I would lean towards the loader framework/CursorLoader to fetch data for your UI. AsyncTask is an option, although it's really a more general purpose threading mechanism. Also, consider an ORM framework that does threading work or maintains a queue of work items for you.
I can't really think of a case where managing a Thread directly would be the best option. It's very low level and lots of room for error when there are nicer abstractions over it.
I've been reading about how to share data between an Activity and a Service. I found some answers here and here. I'm planning on creating a singleton class as this seems like the lowest overhead mechanism to share state.
For my application, I have a service which is acquiring and logging various sensor data and is filling a data structure with the most current state, and then notifying the activity to update the UI with this info, if the activity is visible. If the activity is not visible, then when it becomes visible it consults the state information to update the UI.
I don't see any mention of whether synchronization is necessary. For instance, isn't it possible that the UI thread might be pulling data out of the structure and get interrupted by the service which then puts new data in, resulting in the UI being rendered incorrectly? Also, I want to put a flag on various pieces of data so the front end knows which pieces have been updated: the service would set a boolean and the activity would clear it. It seems like a similar problem could occur here.
Do I need to worry about this, or is it impossible for the UI thread in the activity and the (e.g.) Listener or Receiver thread in the service to interrupt each other. If they can, is it sufficient to use synchronized methods to access the data structure?
For instance, isn't it possible that the UI thread might be pulling data out of the structure and get interrupted by the service which then puts new data in, resulting in the UI being rendered incorrectly?
Possibly. A Service usually has background threads, whether you create them or you get them from specific Service implementations (e.g., the thread used by IntentService for onHandleIntent()). Synchronization is not an issue of components (activities, services, etc.), but rather an issue of threads.
If they can, is it sufficient to use synchronized methods to access the data structure?
Well, personally, I try to use synchronized objects and collections from java.util.concurrent and java.util.concurrent.atomic. Depending on what you're doing and how you're doing it, synchronized methods may be a fine solution.
I have looked through many examples/tutorials of using SQLite in Android. Let's say you have an app that uses SQLite, ContentProvider, CursorLoader, a custom CursorAdapter.
Now all major examples of this that I've found rely on a CursorLoader to fetch data to the CursorAdapter, which by the nature of CursorLoader happens in an Async - UI thread safe manner. However, these same examples all make insert/delete/update calls through the ContentResolver on the main thread (e.g. from onClick, onResume, onPause). (Example) They don't wrap these calls in an AsyncTask or launch a separate thread or use the AsyncQueryHandler.
Why is this, how can so many well written blogs/examples make such an obvious mistake? Or are simple single row insert/delete/update calls so quick that they are safe enough to launch from the Main/UI thread? What is the proper way to do these quick calls?
I also got confused about the samples making calls on the main thread. I guess the samples just simplified the demonstrations avoiding extra threads and callbacks, since single insert/update/delete call may return quickly.
Besides the Loader pattern for query, android did provide a helper class AsyncQueryHandler, since API level 1, for async CRUD operations with full CRUD callbacks supported. The AsyncQueryHandler works inside with a HandlerThread for the async operations and delivers the results back to the main thread.
So I do believe the ContentProvider queries should run in worker threads other than the UI, and those samples may not be best practices according to the official design.
=== edit
Found an annotation from the official framework docs, see this or this, Line 255:
In practice, this should be done in an asynchronous thread instead of
on the main thread. For more discussion, see Loaders. If you are not
just reading data but modifying it, see {#link android.content.AsyncQueryHandler}.
=== edit 2
Link to actual android dev guide containing the above quote
This question has been on my mind since a long time. I guess, this depends on the complexity of the file we are trying to Insert, Update or Delete. If our application is going to Insert or Update large files, it would be always right to do it asynchronously and if the files aren't going to be that big, running it on UI thread can be done.
However, it is always recommended to continue with Database operations on a separate thread.
I think you've answered your own question. I do believe CursorLoader extends AsyncTaskLoader. Calls made from UI thread only process the call TO the CusorLoader (which uses AsyncTask.) What is being done BY the call still does not occur on UI Thread. Making a call to a method/function that then runs things on a seperate thread is still doing work away from UI thread.
What work do you think is happening on the UI thread?
Please show Debug log if possible or example where you think work is done on UI.
It shouldn't be.
Not trying to argue just want to know how you've come to the conclusion of UI work?
When the user logs in into my app. I am starting an asynctask to maintain the user session. And that async task is running indefinitely till the user logs out. My problem is that when I try to start other asynctasks, their doInBackground() method is never executed.
I read somewhere that if an async task is already running, we cannot start new async task. I can confirm this because when i removed the user session async task, it worked properly. Is there a workaround?
P.S.: I have already used executeOnExecutor() method. but it didn't help.
For potentially long running operations I suggest you to use Service rather than asynctask.
Start the service when the user logs in
Intent i= new Intent(context, YourService.class);
i.putExtra("KEY1", "Value to be used by the service");
context.startService(i);
And stop the service when the user logs out
stopService(new Intent(this,YourService.class));
To get to know more about Service you can refer this
Service : Android developers
Service : Vogella
To know more about asynctask vs service you can refer this
Android: AsyncTask vs Service
When to use a Service or AsyncTask or Handler?
I read somewhere that if an async task is already running, we cannot start new async task.
Yes,That is fact that you can't run more then 5 (five) AsyncTaskat same time below the API 11 but for more yes you can using executeOnExecutor.
AsyncTask uses a thread pool pattern for running the stuff from doInBackground(). The issue is initially (in early Android OS versions) the pool size was just 1, meaning no parallel computations for a bunch of AsyncTasks. But later they fixed that and now the size is 5, so at most 5 AsyncTasks can run simultaneously.
I have figure out Some Threading rules and i found one major rule is below ,
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
What is definition of AsyncTask?
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
How & Where use it?
AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended to use it.
Why you can't use multiple AsyncTask at same time ?
There are a few threading rules that must be followed for this class to work properly:
The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Running multiple AsyncTasks at the same time — not possible?
Test sample of parallel excution of AsyncTasks
Try Executor
You should go with Executor that will mange your multiple thread parallel.
Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
...
Sample Example 1
Sample Example 2
Just like a few others here, I object to the premise of the question.
Your core problem is that you are using an AsyncTask to perform a task beyond its scope. Others have noted this too. Those who offer solutions that can mitigate your problem through low-level threads (even java.util.Concurrent is low-level which is why Scala uses Akka actors as an abstraction), Service, etc. are quite clever, but they are treating the symptom rather than curing the disease.
As for what you should be doing, you are not the first to want to maintain a user session in an Android application. This is a solved problem. The common thread (no pun intended) in these solutions is the use of SharedPreferences. Here is a straightforward example of doing this. This Stack Overflow user combines SharedPreferences with OAuth to do something more sophisticated.
It is common in software development to solve problems by preventing them from happening in the first place. I think you can solve the problem of running simultaneous AsyncTasks by not running simultaneous AsyncTasks. User session management is simply not what an AsyncTask is for.
If you are developing for API 11 or higher, you can use AsyncTask.executeOnExecutor() allowing for multiple AsyncTasks to be run at once.
http://developer.android.com/reference/android/os/AsyncTask.html#executeOnExecutor(java.util.concurrent.Executor, Params...)
I'll share with you, what we do on our App.
To keep user Session (We use OAuth with access/refresh tokens), we create a Singleton in our Application extended class. Why we declare this Singleton inside the MainApplication class? (Thats the name of our class), because your Singleton's life will be tided to the Activity that has created it, so if your Application is running on low memory and Garbage Collector collects your paused Activities, it will release your Singleton instance because it's associated to that Activity.
Creating it inside your Application class will let it live inside your RAM as long as the user keeps using your app.
Then, to persists that session cross application uses, we save the credentials inside SharedPreferences encrypting the fields.
yes starting 2 or more asynctasks simultaneously may cause issues on some devices. i had experienced this issue few months back. i could not predict when the 2nd asyncTask would fail to run. The issue was intermittent may caused by usage of memory as i was executing ndk code in asynctask. but i remember well that it depended on memory of device.
Similar question had been asked before. I would post the link for the similar question.
AsyncTask.executeOnExecutor() before API Level 11
Some users suggest go for Service. My advice is don't go for that path yet. Using service is much more complicated. Even you are using service, you still have to deal with threading, as
Note that services, like other application objects, run in the main
thread of their hosting process. This means that, if your service is
going to do any CPU intensive (such as MP3 playback) or blocking (such
as networking) operations, it should spawn its own thread in which to
do that work....
If we can solve a problem in elegant way, don't go for the complicated way.
I would suggest that, try one of the APIs in java.util.concurrent as suggested in below
AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. AsyncTasks
should ideally be used for short operations (a few seconds at the
most.) If you need to keep threads running for long periods of time,
it is highly recommended you use the various APIs provided by the
java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and
FutureTask.
I can't give you any code example so far, as I do not know how you design your session managing mechanism.
If you think your long running session managing task shouldn't bind to the life cycle of your main application life cycle, then only you might want to consider Service. However, bear in mind that, communication among your main application and Service is much more cumbersome and complicated.
For more details, please refer to http://developer.android.com/guide/components/services.html, under section Should you use a service or a thread?