Most of the Android application code runs in the context of components, such as Activity, Service, ContentProvider, or BroadcastReceiver. Let us consider how the interaction of these components with streams is organized in the Android system.
When an application is launched, the system performs a number of operations: it creates an OS process with the same name as the application package name, assigns a unique user identifier to the created process, which is essentially a Linux user name. The system then launches Dalvik VM where the main application thread is created, also called the “user interface thread (UI thread)”. This stream runs all four components of the Android application: Activity, Service, ContentProvider, BroadcastReceiver. The execution of the code in the user interface thread is organized by means of an “event loop” and a message queue.
Consider the interaction of the Android system with the components of the application.
Activity. When the user selects a menu item or clicks on the on-screen button, the system will arrange this action as a message (Message) and place it in the user interface thread queue (UI thread).
Service. Based on the name, many mistakenly believe that the Service (Service) works in a separate thread (Thread). In fact, the service works just like an Activity in a user interface thread. When the local service starts with the startService command, a new message is placed in the main thread queue, which will execute the service code.
')
BroadcastReceiver. When creating a broadcast message, the system places it in the queue of the main application thread. The main stream will later download the BroadcastReceiver code that is registered for this type of message, and will start its execution.
ContentProvider. Calling a local ContentProvider is a bit different. The ContentProvider is also executed in the main thread, but its call is synchronous and does not use a message queue to run the ContentProvider code.
Based on the foregoing, it can be noted that if the main thread is currently processing user input or performing another action, the execution of the code received in the new message will start only after the current operation is completed. If any operation in one of the components requires significant execution time, the user will encounter either jerk animation, or unresponsive interface elements or an “Application does not respond” (ANR) message.
To solve this problem, the parallel programming paradigm is used. In Java, the concept of a thread is used to implement it.
Thread : a thread, a thread of execution, sometimes also referred to as a thread, can be viewed as a separate task, in which an independent set of instructions is executed. If your system has only one processor, then the threads are executed alternately (but the rapid switching of the system between them creates the impression of parallel or simultaneous operation). The diagram shows an application that has three threads:

But, unfortunately, there is little use for user interaction. In fact, if you look closely at the diagram above, you will understand that as soon as the flow has completed all the instructions it contains, it stops and stops tracking user actions. To avoid this, you need to implement an infinite loop in the instruction set. But there is a problem how to perform an action, for example, to display something on the screen from another stream, in other words, how to hook into an infinite loop. For this, Android can use the Android Message System. It consists of the following parts:
Looper : which is also sometimes called the “event loop” is used to implement an infinite loop that can receive tasks used. The Looper class allows you to prepare Thread to handle repetitive actions. Such a Thread, as shown in the figure below, is often called Looper Thread. The main stream of Android is actually Looper Thread. Looper is unique for each thread, it is implemented as a
TLS design pattern or Thread Local Storage (the curious can look at the
ThreadLocal class in the Java documentation or Android).
Message : message is a container for a set of instructions that will be executed in another thread.
Handler : This class provides interaction with Looper Thread. It is with the help of Handler that it will be possible to send a Message with the implemented Runnable to the Looper, which will be executed (immediately or at a specified time) by the thread with which the Handler is connected. The code below illustrates the use of Handler. This code creates an Activity that will complete after a certain period of time.
public class LaunchActivity extends Activity {
HandlerThread : writing a code for a thread implementing a Looper may not be an easy task, so as not to repeat the same errors, the Android system includes the class HandlerThread. Contrary to the name, this class does not handle Handler and Looper.
The practical implementation of this approach can be studied using the
IntentService class code as an example; this class is well suited for performing asynchronous network or other requests, since it can take tasks one by one without waiting for the full processing of the current one, and completes its work independently.
Performing operations in a separate thread does not mean that you can do anything you want without affecting system performance. Never forget that the code you write works on machines that are usually not very powerful. Therefore, you should always use the opportunities provided by the system for optimization.
Based on materials AndroidDevBlog