Android has a lot of different facilitations of executing code on separate threads concurrently. But I'm not sure when each one should be used or what the best practices are for these different ways.
When/Why should Handlers be used?
When/Why should Loaders be used?
When/Why should AsyncTasks be used?
When/Why should FutureTask be used?
When/Why should Executor be used?
When/Why should Threads/Runnables be used?
When/Why should Volley be used?
Have I missed any?
Thanks very much for the help!
As explained before, in order to achieve a scalable application in a multicore device environment, the Android developer should be capable of creating concurrent lines of execution that combine and aggregate data from multiple resources.
Processor with 2 core will handle 2 threads at a time( concurrent execution of two threads). Processor with 4 core will handle 4 threads at a time( concurrent execution of four threads.
For example, Java Swing and Android UI both use a single threaded model where a single UI thread is responsible for updating all the UI.
A deadlock occurs when a thread enters a waiting state because a required resource is held by another thread, which is also waiting for a resource held by the first thread. If the app's main thread is in this situation, ANRs are likely to happen.
You have a pretty big list of components each of which address slightly different things. The two main conflicts in my experience are actually between Handlers vs. Executors, and Tasks vs. Threads.
Threads are the underlying system mechanism used to facilitate concurrency. Threads exist in Windows, Unix, etc., and may be implemented in any way a system sees fit. It is usually pretty expensive to create threads (and even-more-so to create entirely new processes). I do no know whether the Dalvik VM relies on Linux thread or provides its own Thread implementation. According to this Dalvik Virtual Machine Architecture document, the Dalvik VM simply uses the Linux threading model for its thread implementation. The Dalvik VM does not, however, conform to the Java Language Specification's memory model pre Android 4.0.
As you may know, because it is expensive to create threads, a better way to schedule lots of asynchronous computations is to use a managed pool of threads (size depending on the capabilities of your underlying hardware) and simply feed the tasks to the manager, which, in turn, schedules the tasks on threads as they become available.
A short overview of the history as I understand it is that Android development began back in the days before the Java Executor libraries/api became solidified. To provide a less confusing concurrency interface than the old Threads and Synchronization methods available, and to facilitate message passing between threads in a nice manner, Android introduced Handlers. However, unless I'm understanding this incorrectly, Handlers are basically the same thing as Executors. You pass Messages (containing Runnables), or simply Runables, to Handlers and these messages get queued and executed as quickly as the Handler's Thread can well.. handle them.
In Android, all communication between threads is (or should be) done via a thread's handler (to my knowledge and excluding situations where you're directly accessing another threads memory and synchronization may be required). In new Java, Executors are functionally equivalent to Handlers, and FutureTasks are equivalent to Messages. Runnables are still Runnables. A Runnable is used when code simply needs to be executed. A FutureTask is used when a computation needs to be executed asynchronously and a result needs to be retrieved from the computation. The result can by any type of object. Because FutureTask implements the Future interface, you may also easily wait in one thread for the Future to resolve and get the result.
Loaders are simply an attempt at providing a reusable mechanism for loading data (to be consumed by an activity). Despite the documentation, the Loader class is not abstract nor does it need to be used solely for the asynchronous acquisition of data (although I can't think of a case where you'd use it for synchronous loading, I have not explored that). The AsyncTaskLoader simply uses an AsyncTask to execute the Loader's methods responsible for loading data. Loaders are not necessary at all.
Threads should be used to back Executors or Handlers, or, in other cases, you will know when you need a thread (such as to back a Service). You should generally avoid Threads for small tasks that are created, executed, and destroyed in a liberal manner.
In my experience, it seems better to stick with Handlers when dealing with message passing between your UI thread (running an Activity and/or View hierarchy) and some other thread. However, it seems perfectly safe to use either Executors or Handlers when implementing your own asynchronous functionality. For example, I may have a class that manages a queue of images to be fetched from a server. I can simply create my own executor and feed tasks to that executor as I see fit. But, when passing a message message back to the Activity that one of the images has loaded and the view should be set with the resulting data, I've had best results using the Activity's Handler (accessed via the runOnUiThread()
method) as opposed to creating an executor that runs on the Activity's thread and posting Runnables to it. It is unclear why the latter would not work all the time (from the documentation, that is) but I suspect doing so can result in behavior similar to a Handler's runWithScissors()
method. (Edit, I'm now aware it is extremely bad practice to run multiple concurrent "loopers" on one thread -- so that explains that.)
I guess a good rule of thumb may be to:
As stated earlier, Runnables are a simple interface used to pass computations between objects. You need not use Runnables only when threads/executors/handlers are involved -- they can be used to capture state and to reuse code.
I don't use Loaders. But, they may be used when you have data that you need to load in order for an Activity to use it. You can use a CursorLoader with a ContentProvider if you are following the ContentProvider idiom in terms of handling data.
I've never used volley so I doubt I have any useful insight on that channel.
Disclaimer: I am not an authority on Android history. Regardless, I hope the overview helps add clarity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With