Skip to content

Latest commit

 

History

History
112 lines (61 loc) · 8.32 KB

File metadata and controls

112 lines (61 loc) · 8.32 KB

Threading

Making adept use of threads & processes on Android can help you boost your app’s performance.

Process and Thread

  • All are execution environment. Process can consist of 1 or many thread(s) but a thread can only belong to 1 process.
  • Context switching: Store the state of process or thread for resume later. Allow multi process to share a single CPU.
  • AsyncTask will be execute serially by default on Android API >= 13. Because of that it will block other AsyncTask. To resolve this we use ThreadpoolExecutor to execute parallel.
Process Thread
Heavy weight Light weight
Process creation is costly Thread creation is economy
Not share memory Memory shared between threads in same process
IPC is slow because too many addresses Communication between threads is fast because they shared mem address
Forced to communicate via messages

Android Threads

Runnable

A runnable isn't a background thread, it is a unit of work that can be run in a given thread.

Handler

...

When to use Handler#post() and when to use Thread#start().

  • Use Handler.post() whenever you want to do operations in the UI thread. So let's say in the callback (which is running in separate thread) you want to change a TextView's text, you should use Handler.post().

  • If whatever you are doing is "heavy" you should be doing it in a Thread (That's why network operation is forced to do in a worker thread in Android). Interestingly when you are using a separate worker thread it is often useful to also use a Handler to communication between this working thread and the main UI thread.

  • Must note that: Handler and Thread are really 2 different things and do NOT contradict each other. Handler can be used to attach to a thread and provides a simple channel to send data to this thread. And a Thread is basically the core element of multithreading which a developer can use to get heavy payload work off main thread.

  • The difference between Hander.post() and View.post() is that Handler will run your code on the thread the Handler instance was created on (which is not necessarily the UI thread) because it will be attached to the only looper of this thread to communicate, while View will always run it on the UI thread (because views are bound to it).

HandlerThread

You would use HandlerThread in case that you want to perform long background tasks sequentially, one at a time and you want that those tasks will run at the order of execution. The HandlerThread has it's own looper and handlers could be created and post it, (so it would not block the main thread). And use the Handler inside it to communication between the worker thread and the caller thread.

For more information related to performance, see this and this.

For real life example, look at this.

Ways to get work off main thread.

Every Android app has a main thread which is in charge of handling UI (including measuring and drawing views), coordinating user interactions, and receiving lifecycle events. If there is too much work happening on this thread, the app appears to hang or slow down. Any long-running computations/operations that takes more than a few millisecs (such as decoding a bitmap, accessing the disk, or performing network requests,..) should be done on a separate background thread

There are some ways for your app to perform operations in the background without hurting app performance. See this to see when to use which approach.

Normal Thread

Implement a Runnable by overriding and place the code that need to be executed inside Runnable.run() method. Then create a new thread using Thread t = new Thread(Runnable runnable); and start it with t.start(). (Bad practice, thread creation is costly).

AsyncTask

AsyncTask is a proper and easy use to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.

To use it, you must subclass AsyncTask and implement the doInBackground() callback method, which runs in a pool of background threads. To update your UI, you should implement onPostExecute(), which delivers the result from doInBackground() and runs in the UI thread, so you can safely update your UI. You can then run the task by calling execute() from the UI thread.

See this example. (Quick solution but known source of memory leaks).

ThreadPools

ThreadPools provide a group of background threads that accept and enqueue submitted work.

ThreadPoolExecutor is an ExecutorService that executes each submitted task from a queue, when a thread in its pool becomes free/available.

Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks.

Create new group of ThreadPools base on your need (network, disk I/O, and computation,..) using Executor executor = Executors.newFixedThreadPool(int) (fixed size thread pool) and execute task using executor.execute(Runnable). (Recommended - reuse threads to avoid thread creation cost)

Worker Thread

Create a custom worker thread.

HandlerThread

HandlerThread Handy class for starting a new thread that has a looper.

Create a new HandlerThread and invoke start() the same as normal Thread. And use Handler - part of the Android system's framework for managing threads - to communicate by receiving messages. See this.

IntentService

IntentService is a base class for Service that handle asynchronous requests (expressed as Intents) on demand

Create a new class that extends IntentService and implement it. Then clients send requests through Context.startService(Intent) to pawns a new worker thread to handle task and automatically stops itself when it runs out of work.

See this.

Using external libraries:

  1. WorkManager is part of Android Jetpack, a lib that gracefully runs deferrable background work when the work's triggers (like appropriate network state and battery conditions) are satisfied. Recommended for work that must execute to completion and is deferrable.
  2. RxJava Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.

Race condition

A race condition occurs when two or more threads can access shared data and they try to change it at the same time. The shared data part is called "critical section". To resolve conflict, race condition Java sync is NOT enough -> blocking thread.

  • vilotile: Ensure anythread that read a field will see the most recently value.
synchronize lock
Java use monitor lock Need help of system
Easy to use Need to try/catch exception to release the lock