According to EventBus doc, there are 4 types of thread modes which EventBus uses to deliver threads:
onEvent()
PostThread
Good for simple tasks
onEventMainThread()
MainThread
a.k.a. UI Thread
Good for UI changes
onEventBackgroundThread()
BackgroundTread
Using single thread, delivering events sequentially.
Good for execution requiring moderate amount of time.
onEventAsync()
Async
Using separate threads.
Good for execution requiring longer time
Question
What are some criteria I should examine before I use onEventBackgroundThread() over onEventAsync(), or vice versa? What would be some examples of using one over the other with obvious advantages?
Which thread modes should each of the following functions use?
Getting the device status -- GPS location of the device (i.e. android.location), Internet connectivity status (i.e. ConnectivityManager, NetworkInfo).
Making simple HTTP requests to receive text (e.g. JSON), taking anywhere between 1000ms to 5000ms, average 2000ms.
Making simple HTTP requests to load images with file sizes between 50kb to 1500kb (exact sizes are unknown to client, before making requests to server).
Caching data to internal database (e.g. SharedPreferences, SQLite, etc).
What are some criteria I should examine before I use onEventBackgroundThread() over onEventAsync(), or vice versa? What would be some examples of using one over the other with obvious advantages?
Well, it's pretty much as the bullets outline. If you don't mind queued, one-at-a-time processing (or perhaps you want it for simpler thread safety), use onEventBackgroundThread(). If you need to do several of them in parallel, particularly if they are I/O-bound, you'd use onEventAsync().
Which thread modes should each of the following functions use?
GPS location of the device (i.e. android.location)
None of the above. LocationManager and the fused location API have their own asynchronous options; I'd use those. Once you get the location handed to you, you could post an event with the location data, but then the threading is dictated by the subscribers to that event, not the poster.
Internet connectivity status (i.e. ConnectivityManager, NetworkInfo)
None of the above, as AFAIK getNetworkInfo() is not an expensive call.
Making simple HTTP requests to receive text (e.g. JSON), taking anywhere between 1000ms to 5000ms, average 2000ms.
None of the above. I'd use Retrofit or another HTTP client library that offers asynchronous options. If for some reason you absolutely have to do the HTTP I/O yourself, it would depend on how frequently this was happening. If, for example, you might fall behind because you fire off several of these in rapid succession, use onEventAsync() so they can run in parallel.
Making simple HTTP requests to load images with file sizes between 50kb to 1500kb (exact sizes are unknown to client, before making requests to server).
None of the above. Use Picasso, Universal Image Loader, or any of the other image-loading libraries, as they all have asynchronous options, and you really need those anyway for the image processing logic. If for some reason you absolutely have to do the HTTP I/O yourself, it'd follow the same rules as I described for the previous item.
Caching data to internal database (e.g. SharedPreferences, SQLite, etc).
Assuming that you're not using some wrapper library here that might offer asynchronous operation, this probably can be handled via onEventBackgroundThread(). That would also give you the advantage of ensuring serialized operation.
Related
I have an Android app that will be receiving rapid data over bluetooth (BLE). The data will be arriving at 50-100 Hz from a remote sensor device into a dedicated service (the Nordic nRF BLE manager) on an Android smartphone. I want to hand the data, at full rate, to a separate service to compute analytics on it. If I use an IntentService for the analytics, that means intents will come in every 10 milliseconds. I'm sure there is significant overhead for each Intent and I doubt it was designed for this much data. But everything I read suggests that this is the simplest solution. Is this the right approach? Thanks.
First of all you need to decide whether you need real-time behavior. The data is being received over BLE in real-time, but do you really need to process it in real time? If the analytics that you're computing are not required in real-time, then it is ok to receive the data, store it, and process later.
If you really need real-time data processing then IntentService is not an adequate design choice.
If you don't need real-time data processing then IntentService can work, but will be non-optimal from performance point of view.
There will be two overheads.
The first one you found by yourself - sending intent bears some additional overhead because the OS needs to "route" the intent to the service.
The second one will be associated with starting and stopping the IntentService. If the period of time between intent arrivals will be lower than the time it takes onHandleIntent() to return, then the system will be starting and stopping the IntentService for each intent. This overhead is much higher that the first one.
Therefore, even though IntentService can work in this situation, IMHO you shouldn't use this approach.
The best solution to this problem will be to use bound Service. Bind to it from the BLE receiver and send the data using regular method calls. The downside is that you'll need to implement two features by yourself:
Blocking queue for data that needs to be processed
The logic that offloads the processing to background thread
Writing this logic is not trivial, but if your application is a serious project, then it is the only right thing to do IMHO. You can copy-paste threading logic from the source code of IntentService.
One word of caution: you must be aware of excessive memory consumption. For example: if you use a single background thread for processing, and the rate of incoming data is higher than the rate of processing, then your queue will be constantly growing. In such a situation, if given enough time, your application will crash with OutOfMemory exception (can happen with IntentService too).
If this happens, you'll need to do either of:
Use multiple threads for background processing
Store data into SQLite (but then SQLite can grow excessively)
Drop some data
IntentService has embedded queue of incoming Intents, so, if you process intents slower than they arrive, it is possible to do.
But, I'd use HandlerThread for posting incoming data within Message onto it. It has embedded message queue too, but there is no overhead, as with creating IntentService.
Another approach - use ordinary Service and handle backpressure with RxJava library.
I have to send four different request in an api at the same time. Do i need to make AsyncTask background thread for each request or all request could be done through a single AsyncTask. Can somebody please help.
This is a concurrency issue. There is literally dozens of ways to do this in Android. I've written almost every single one for courses that cover this material... and even then it isn't 'simple'.
I'd personally make use of HaMeR (Handler, Messages, Runnable) framework of Android. Create 4 runnables and have them post their results to a Handler.
However... That isn't the easiest to implement. and would require you to understand how to safely create your own custom handler (making use of WeakReference properly, etc.)
Therefore, I'd recommend running the asyncTask(s) on the executorService
myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); The default thread pool executor should start with 4 threads (I believe off-hand without looking it up).
I am assuming you are using HttpURLConnections. Unfortunately each of those connections, as specified in the documentation, is capable of handling only a single request.
However, you can (and possibly should) still perform all your requests in a single AsyncTask. Each AsyncTask will require the creation of a new thread which takes lots of time and resources. So don't listen to anyone who tells you to create a new task for each request.
You also have the option of exploiting HTTP persistence. If you add the header Connection: Keep-Alive to your request via connection.setRequestProperty("Connection", "Keep-Alive");, you will be able to send multiple requests over the same connection and save a lot of time and resources.
It's a little complicated in Java, because of the one-request-per-httpurlconnection rule, but it can be done. First, when you are done with your first request's HttpURLConnection do not close that connection. Then, to create the next connection, call url.openConnection() on the same URL object that you used to create your first HttpURLConnection. The JVM will know to reuse that connection if possible to save bandwidth.
You also have the option of using HTTP/2.0 multiplexing, which allows you to send multiple requests literally at the same time. Unfortunately I am not yet well versed enough in HTTP/2.0 to tell you exactly how to make use of this, but the multiplexing feature was included to solve exactly this problem.
I have been reading a lot about network operations with android and how to do it properly. The documentation suggests using Volley and it abstracts the process making the network request:
http://developer.android.com/training/volley/simple.html
As I use Retrofit in my app I thought that the best practice was to use Loaders as they behave well on orientation change, but I found this:
http://www.androiddesignpatterns.com/2012/08/implementing-loaders.html
"Using a Loader to perform network requests isn't great practice, because (1) it means that your application will be hard on the battery (having to poll for new data from the network repeatedly each time you start the Activity, (2) there is no way to observer the network for content changes without polling it repeatedly, and (3) your application won't work offline."
(1) isn't particularly true because you can just resume the loader on activity creation. I don't think I fully understand point (2) and point (3) isn't a concern for me as there is no way for my app to work properly offline.
However, this caught my eye, again, from the same link.
"So my answer is to forget about using the Loader/AsyncTask combination entirely and to stick with a Service. The Service can poll the network for data every once and a while and insert new data into a ContentProvider. You can then use a CursorLoader to load data from the ContentProvider without it needing to know anything about where the data coming from."
Has anyone used this approach of using a Service to poll the network and populate a ContentProvider? I don't think it will work properly with my app as it uses a RESTful API that is constantly requested. I don't think it will be particular effective, but I might be missing something here.
Sorry for the long question. It is not a question exactly, but I wish to create a discussion around the topic.
I'm building a program which interfaces with a device which runs its own internal web server. I communicate with the device via a web API.
Basically what happens is that a GUI is presented to the user, where the user can make certain modifications to the device. These changes are communicated to the device, and results are returned through XML. The device needs to converse with the program in the background more or less continually (say every 15s or so) to update certain values to the user.
My structure that I'm envisioning is something like this:
UI - Main - Networking - XML Parser.
I'm looking for advice on how to manage these. I understand the UI thread should be separate to provide a smooth experience to users. I also understand that the networking should be at least an asynchronous task. I'm not so sure about how to handle their interaction, and make sure things are happening smoothly and effectively.
My idea is that Main will handle passing data around, telling the networker to send specific messages or changes, passing the returned XML to the parser, and then passing the parsed values to UI for handling.
I'm curious though for advice beyond that.
Have a look at creating a service that is created with your Activity. Without knowing the details of your plan, a Service looks like the optimal solution to perform all the heavy work.
UPDATE:
You could have the calls to web API run in a Service and, when needed, update the UI through an interface. You would have to instruct the Service to run on its own thread, so thread safety is an issue, but less trouble in the long run than using an AsyncTask.
Have a thought about using Google C2DM.
In your case,
Pros -> Less battery use, coordinated network traffic, Don't have to run a continues service and doesn't have the potential of being killed when the device runs out of resources.
Cons -> You have to post the results manually back to your internal server, and server should know which request the device is replying to. Communication is disconnected and may not be real-time. Requires a google account on the device and Google market.
I'm using Fragments and LoaderManager. I have to launch an unknown number of tasks, and they might be run in parallel (otherwise I'd just reuse one and only one loader). For example, I have a listview, and each row might have a button to save the content of that row to a webserver. The user could initiate a save request on multiple items in parallel.
private int nextId = 0;
private void onClickListener() {
Bundle bundle = new Bundle();
bundle.putNextData(...);
getLoaderManager().initLoader(nextId++, bundle, this);
}
I could try bookkeeping myself, so create a pool of loaders manually and reuse them when possible, seems like it might be something already implemented by the API?
Thanks
I don't think you should use a Loader for saving data to a remote server.
Instead, use an IntentService or something similar to process a queue of "save" operations. This way, your communication with the web server can be batched, collapsed (i.e. multiple queued saves for a single item can be collapsed into one operation), and will live beyond the lifespan of your activity if need be.
A save queue processed by an IntentService (or equivalent) is also a great way to retry failed operations with backoff, since you can implement delayed retries with exponential backoff using AlarmManager.
An IntentService or bound service are always good approaches for that.
As Roman points, note that enqueuing several requests and called them separately is not highly recommended (it is very likely that you give a lot of work to the radio connection - when using data - which among other things drain your battery. Here is must-read about that)
I'd personally recommend to use a bound service with a queue of requests and a pool of threads available (that approach gives you full control for more complex network operations like in your case). There are more details on the approach here and a testcase working example over here.
Update us about your progress.
You are at the right direction, let me just help you a bit.
Reusing is indeed a good idea, and you do not have to worry about it because Android did it for you(Or Java actually ;)
It called ThreadPoolExecuter, you can start as many tasks as you wish and he will only open the predefined number of threads.(Best practice is trying to open as many threads as parallel network connection can be run on the device. From my research it is between 4 - 9).
And if you are trying to download same URL twice may be you can protect your self and open only one task for it.