Android-thread details

Source: Internet
Author: User
Tags call back

Android-thread details
What is a thread?

Thread or thread execution is essentially a string of commands (also program code), and then we send it to the operating system for execution.

In general, our CPU can only process one thread at a time. Multi-core processors (most Android devices are already multi-core), as the name suggests, are capable of processing multiple threads at the same time (generally speaking, they can process multiple tasks at the same time ).

The essence of multi-core processing and single-core multi-task processing

As I mentioned above, not all the descriptions are correct. Because a single core can also be used to simulate multiple threads.

Each task running in a thread can be divided into multiple commands, and these commands do not need to be executed at the same time. Therefore, a single-core device can first switch to thread 1 to execute instruction 1A, then switch to thread 2 to execute instruction 2A, and then return to thread 1 to execute 1B, 1C, and 1D, then switch to thread 2 and execute 2B, 2C, and so on.

The switching between threads is so fast that it also occurs on a single-core device. Almost all threads process tasks within the same time. In fact, this is because of the illusion that the speed is too fast. Just like Brown, a special agent in the movie matrix, many heads and hands can be changed.

Next let's look at some code.

Threads in the Java Core

In Java, if you want to process parallel tasks, your code will be executed in Runnable. You can inherit the Thread class or implement the Runnable interface:

 

// Version 1public class IAmAThread extends Thread {    public IAmAThread() {        super("IAmAThread");    }     @Override    public void run() {        // your code (sequence of instructions)    }}// to execute this sequence of instructions in a separate thread.new IAmAThread().start(); // Version 2public class IAmARunnable implements Runnable {    @Override    public void run() {        // your code (sequence of instructions)    }}// to execute this sequence of instructions in a separate thread.IAmARunnable myRunnable = new IAmARunnable();new Thread(myRunnable).start();

 

These two methods are basically the same. The first version is to create a Thread class. The second version is to create a Runnable object and then a Thread class to call it.

The second version is usually recommended. This is also a big topic. It is beyond the scope of this article and will be discussed later.

Threads on Android

Whenever the APP is started, all components run in a separate thread (default) called the main thread. This thread is mainly used to process UI operations and distribute events for view components and widgets. Therefore, the main thread is also called the UI thread.

If you run a time-consuming operation in the UI thread, the UI will be locked until the time-consuming operation ends. This is terrible for the user experience! This is why we need to understand the thread mechanism on Android. By understanding these mechanisms, you can move some complex jobs to other threads for execution. If you run a time-consuming task in the UI thread, ANR may occur (the application has no response), so that the user will soon end your APP.

Like Java, Android supports using the Thread class in Java for One-Step task processing. So it is easy to use the Android thread like the Java example above, but it still seems a little difficult.

Why is it difficult to use standard Java threads on Android?

In fact, parallel task processing is not as simple as you think. You must ensure concurrency in multiple threads, as the great Tim Bray said: ordinary humans can't do concurrency at scale (or really at all )...

Especially for Android, the following features are slightly bloated:

Asynchronous is a major PITA for UI threads (if you need to update the interface to the main thread in the background thread, you will use it ). If the screen direction or screen configuration changes, some strange phenomena may occur. Changing the screen direction will cause Activity reconstruction (so the background thread needs to change the state of the destroyed Activity. If the background thread is not on the UI thread, the situation will be more complicated, for example, condition 1 ). There is no default processing method for the thread pool. To cancel a thread operation, you must customize the code.

So how to handle concurrent tasks on Android?

You may have heard of some common terms on Android:

1. Handler
This is the detailed topic we will discuss today.

2. AsyncTask
AsyncTask is the easiest way to operate threads on Android and the most error-prone way.

3. IntentService
This method requires more code, but it is a good way to move time-consuming tasks to the background, and also my favorite method. With the use of an EventBus mechanism framework such as Otto, it is very easy to implement IntentService.

4. Loader
There are still many things to do about processing asynchronous tasks, such as processing some data from a database or content provider.

5. Service
If you have used the Service before, you should know that there is a misunderstanding here. One common misunderstanding is that the Service runs in the background thread. Actually not! It seems that they run in the background because they are not associated with the UI components, but they (by default) run on the UI thread ...... Therefore, the system runs on the UI thread by default, and even has no UI parts on it.

If you want to run the service in the background thread, you must define a thread and run the operation code in that thread (similar to the method mentioned above ). In fact, you should use IntentService, but this is not the topic discussed in this article.

Handler on Android

The following is an excerpt from Android developer documentation for Handlers:

> A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. each Handler instance is associated with a single thread and that thread's message queue. when you create a new Handler, it is bound to the thread/message queue of the thread that is creating it-from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

To better understand this concept, you may need to check what is Message Queues.

Message Queue

Basically, there is a message queue in the thread, which is responsible for inter-thread communication. This is a design mode where all control commands or content are transmitted between threads.

A message queue is a command queue for a thread, just like its name. Here we can also do something cooler:

Scheduled messages and threads are executed at a certain time point. You need to add the queuing action in another thread, instead of in this thread.

Note: The concept of "message" is the same as that of Runnable object and command queue.

Return to Handler on Android ...... If you read this document carefully, you can see that the document is as follows:

> A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue.

Therefore, Handler allows you to send messages to the thread queue:

> Each Handler instance is associated with a single thread and that thread's message queue.

A Handler object can only be associated with one thread:

> When you create a new Handler, it is bound to the thread/message queue of the thread that is creating it

So which thread is a Handler associated? Is the thread that creates it.

>-From that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue .,

After learning about this knowledge, please continue reading ......

TIPS: You may not know the following points. Each thread is bound to a Handler instance and can run and communicate with other threads.

There is also a small suggestion (if AsyncTask is used). AsyncTask uses Handler internally for processing, but it does not run in the UI thread. It will provide a channel to communicate with the UI thread, use the postExecute method.

This is cool. How can I create a Handler?

There are two methods:

Use the default constructor: new Handler (). Use the constructor with parameters. A parameter is a Runnable object or callback object. Is there any practical API in Handler?

Remember:

Handler simply sends messages to the Message Queue (or uses the post method). They have more convenient methods to help communicate with the UI thread.

If you look at the Handler API now, you can see these methods clearly:

Post postDelayed postAtTime sample code

The code here is very basic, but you can take a good look at the annotations.

Example 1: use the "post" method of Handler

public class TestActivity extends Activity { // ...// all standard stuff @Overridepublic void onCreate(Bundle savedInstanceState) {     // ...    // all standard stuff     // we're creating a new handler here    // and we're in the UI Thread (default)    // so this Handler is associated with the UI thread    Handler mHandler = new Handler();     // I want to start doing something really long    // which means I should run the fella in another thread.    // I do that by sending a message - in the form of another runnable object     // But first, I'm going to create a Runnable object or a message for this    Runnable mRunnableOnSeparateThread = new Runnable() {        @Override        public void run () {             // do some long operation            longOperation();             // After mRunnableOnSeparateThread is done with it's job,            // I need to tell the user that i'm done            // which means I need to send a message back to the UI thread             // who do we know that's associated with the UI thread?            mHandler.post(new Runnable(){                @Override                public void run(){                    // do some UI related thing                    // like update a progress bar or TextView                    // ....                }            });          }    };     // Cool but I've not executed the mRunnableOnSeparateThread yet    // I've only defined the message to be sent    // When I execute it though, I want it to be in a different thread    // that was the whole point.     new Thread(mRunnableOnSeparateThread).start();} }

If there is no Handler object at all, it will be difficult to call back the post method.

Example 2: Use the postDelayed Method

In the new features introduced on this site recently, I have to simulate the Automatic completion function of EditText every time. After each text change, an API call is triggered to retrieve data from the server.

I want to reduce the number of API calls by the APP, so I decided to use the postDelayed method of Handler to implement this function.

This example is not applicable to parallel processing, but about how Handler sends messages to the message queue and schedules the execution of messages at a certain point in the future.

// the below code is inside a TextWatcher// which implements the onTextChanged method// I've simplified it to only highlight the parts we're// interested in private long lastChange = 0; @Overridepublic void onTextChanged(final CharSequence chars,                          int start, int before, int count) {         // The handler is spawned from the UI thread        new Handler().postDelayed(             // argument 1 for postDelated = message to be sent            new Runnable() {                @Override                public void run() {                     if (noChangeInText_InTheLastFewSeconds()) {                        searchAndPopulateListView(chars.toString());  // logic                    }                }            },             // argument 2 for postDelated = delay before execution            300);         lastChange = System.currentTimeMillis();} private boolean noChangeInText_InTheLastFewSeconds() {    return System.currentTimeMillis() - lastChange >= 300}
Finally, I left the "postAtTime" method as a contact to the readers. Are you familiar with Handler? If yes, you can use the thread as much as possible. 1. Android Process

Before learning about the Android thread, you must first understand the Android process. When a program is started for the first time, Android starts a LINUX Process and a main thread. By default, all components of the program will run in the process and thread. In addition, Android assigns a LINUX User to each application. Android will try to keep a running process. When the memory resources are insufficient, Android will try to stop some processes and release enough resources for other new processes to use, it can also ensure that the current process being accessed by the user has enough resources to respond to the user's events in a timely manner. Android judges the importance of a process based on the component category and component Status in the process. Android first stops unimportant processes. There are five levels of importance from high to low:

Foreground Process
The foreground process is the process currently in use by the user. Only some foreground processes can exist at any time. They are the last one ended, when the memory is low to the root of them can not run. In general, in this case, the device will perform memory scheduling and stop some foreground processes to maintain a response to user interaction. Visible Process
The visible process does not contain foreground components, but displays a visible process on the screen. It is very important, unless the foreground process needs to obtain its resources, it will not be aborted. Service Process
A service started using the startService () method is running. This service is not of the two higher importance mentioned above. Although the process where the service is located is not directly visible to users, they execute tasks that users are very concerned about (such as playing mp3 and downloading data from the network ). As long as the foreground and visible processes have enough memory, the system will not recycle them. Background Process
An activity that is invisible to users is running (the onStop () method has been called ). these processes have no direct impact on the user experience. They can be recycled when the service process, visible process, and frontend process require memory. Generally, many invisible processes are running in the system. They are stored in the LRU (least recently used) list so that they can be recycled immediately when the memory is insufficient. If an activity executes its lifecycle, closing the process has no significant impact on user experience. Empty Process
No program components are running. The only reason for running these processes is to use them as a cache to shorten the restart time required by the next program. The system often terminates these processes, which can regulate the balance between the program cache and the system cache.

When Android rates the importance of processes, it selects the highest level. In addition, when another process is dependent, the level of a process may increase. A process serving other processes is never more important than the process being served. Because the service process is more important than the background activity process, it is best to start a service for a time-consuming activity to do this work, instead of starting a sub-process, this operation takes longer time than the activity. For example, playing music in the background and uploading images captured by cameras to the Internet. Using the service, processes can obtain at least the important level of the service process, you do not need to consider the current status of the activity. Broadcast receivers should also enable a service rather than opening a thread when it is time-consuming.

2. Single-threaded Model

When a program is started for the first time, Android starts a corresponding Main Thread at the same time. The Main Thread is mainly responsible for processing UI-related events, such as user key events, the user contacts screen events and Screen Drawing events, and distributes related events to corresponding components for processing. Therefore, the main thread is often called the UI thread. When developing Android applications, you must follow the single-thread model principle: Android UI operations are not thread-safe and must be executed in the UI thread.

2.1 The Sub-thread updates the UI

The Android UI is Single-threaded. To avoid dragging the GUI, some time-consuming objects should be handed over to independent threads for execution. If the background thread executes the UI object, Android sends an error message CalledFromWrongThreadException. When such an exception is thrown in the future, you must know what is going on!

2.2 Message Queue

In the single-thread model, Android designs a Message Queue to solve similar problems. The Message Queue can be used between threads to exchange information with Handler and logoff components. They are described as follows:

1. MessageMessage refers to the information exchanged between threads. When the background thread needs to update the UI for processing data, a Message containing some data is sent to the UI thread. 2. HandlerHandler is the main handler of the Message, responsible for sending the Message and executing the Message content. The background thread uses the passed Handler object reference to sendMessage ). When Handler is used, the handleMessage (Message) method of implement class is required. It is the operation content for processing these messages, such as Update UI. It is usually necessary to subclass Handler to implement the handleMessage method. 3. Message QueueMessage Queue Message Queue, which is used to store messages published by Handler and run first-in-first-out. Each message queue has a corresponding Handler. Handler sends a message to the message queue in two ways: sendMessage or post. Both messages are inserted at the end of the message queue and executed first-in-first-out. However, messages sent using the two methods are executed in a slightly different way: a message object is sent using sendMessage, which will be processed by the handleMessage () function of Handler; the post method sends a runnable object, which is executed by itself. 4. looperloue is the manager of the Message Queue in each line. Android does not have a Global Message Queue, while Android automatically creates a Message Queue for the main thread (UI thread), but no Message Queue is created in the Child thread. Therefore, the logoff value of the main thread obtained by calling logoff. getmainlogoff () is not NULL, but the logoff value of the current thread may be NULL by calling logoff. mylogoff.

The API Doc provides the correct method for using logoff for sub-threads:

Class LooperThread extends Thread {public Handler mHandler; public void run () {loid. prepare (); // create the Logoff of this thread and create a MessageQueue mHandler = new Handler () {public void handleMessage (Message msg) {// process incoming messages here }}; logoff. loop (); // start logoff and listen to Message Queue }}

The general process of this Message mechanism:

1. After the logoff. loop () method starts running, the non-NULL Message in the Message Queue is retrieved cyclically in the receiving order.

2. At the beginning, all messages in the Message Queue are NULL. When Handler. sendMessage (Message) is sent to Message Queue, this function sets the target attribute of the Message object to the current Handler object. Then logoff retrieves the Message, and calls the dispatchMessage function of the Hander to which the target of the Message points to process the Message.

In the dispatchMessage method, the user determines how to process the Message. The priority ranges from high to low:

1) Callback in the Message, an object that implements the Runnable interface, where the run function is used for processing;

2) The mCallback in Handler points to an object that implements the Callback interface, which is processed by the handleMessage;

3) the classes corresponding to the Handler object for processing messages inherit and implement the handleMessage function. The handleMessage function is used to process messages.

We can see that the handleMessage method we implemented has the lowest priority!

3. After Handler processes the Message (update UI), logoff sets the Message to NULL for recycling!

There are many articles on the Internet about how the main thread interacts with other sub-threads, how information is transmitted, and who finally processes information, my personal understanding is the simplest method-this thread is used to determine which thread the logoff object in the Handler object belongs! 1. if the parameter of the constructor of the Handler object is null, It is the Logoff of the current thread; 2. logoff. getmainlogoff () is the logoff object of the main thread. mylogoff () obtains the logoff object of the current thread.

Let's take an example to simulate the process of retrieving data from the network and loading data to ListView:

Public class ListProgressDemo extends ListActivity {@ Override public void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. listprogress); (Button) findViewById (R. id. load_Handler )). setOnClickListener (new View. onClickListener () {@ Override public void onClick (View view) {data = null; data = new ArrayList
 
  
(); Adapter = null; showDialog (PROGRESS_DIALOG); new ProgressThread (handler, data ). start () ;}}) ;}@ Override protected dited onCreateDialog (int id) {switch (id) {case PROGRESS_DIALOG: return ProgressDialog. show (this, "", "Loading. please wait... ", true); default: return null;} private class ProgressThread extends Thread {private Handler handler; private ArrayList
  
   
Data; public ProgressThread (Handler handler, ArrayList
   
    
Data) {this. handler = handler; this. data = data ;}@ Override public void run () {for (int I = 0; I <8; I ++) {data. add ("ListItem"); // try {Thread for background data processing. sleep (100);} catch (InterruptedException e) {Message msg = handler. obtainMessage (); Bundle B = new Bundle (); B. putInt ("state", STATE_ERROR); msg. setData (B); handler. sendMessage (msg) ;}} Message msg = handler. obtainMessage (); Bundle B = new Bundle () B. putInt ("state", STATE_FINISH); msg. setData (B); handler. sendMessage (msg) ;}// you do not even need to set logoff here, because Handler uses the logoff private final Handler of the current thread by default. getMainLooper () {public void handleMessage (Message msg) {// process Message, update ListView int state = msg. getData (). getInt ("state"); switch (state) {case STATE_FINISH: dismissDialog (PROGRESS_DIALOG); Toast. makeText (getApplicatio NContext (), "Loading complete! ", Toast. LENGTH_LONG). show (); adapter = new ArrayAdapter
    
     
(GetApplicationContext (), android. r. layout. simple_list_item_1, data); setListAdapter (adapter); break; case STATE_ERROR: dismissDialog (PROGRESS_DIALOG); Toast. makeText (getApplicationContext (), "An error occurred during the processing! ", Toast. LENGTH_LONG). show (); adapter = new ArrayAdapter
     
      
(GetApplicationContext (), android. R. layout. simple_list_item_1, data); setListAdapter (adapter); break; default :}}; private ArrayAdapter
      
        Adapter; private ArrayList
       
         Data; private static final int PROGRESS_DIALOG = 1; private static final int STATE_FINISH = 1; private static final int STATE_ERROR =-1 ;}
       
      
     
    
   
  
 

In this example, I thought it was a bit messy after writing it. I had to sort it out to understand the process of interaction between threads and the changes before and after data. Then I learned about the AsyncTask class. After modification, I can easily understand it!

2.3 AsyncTaskAsyncTask:
(Button) findViewById (R. id. load_AsyncTask )). setOnClickListener (new View. onClickListener () {@ Override public void onClick (View view) {data = null; data = new ArrayList
 
  
(); Adapter = null; // display ProgressDialog to AsyncTask. onPreExecute () // showDialog (PROGRESS_DIALOG); new progresstask(.exe cute (data) ;}}); private class ProgressTask extends AsyncTask, Void, integer> {/* This method will be called by the UI thread before the actual background operation is executed. You can make some preparations in this method, such as displaying a progress bar on the interface. * // @ Override protected void onPreExecute () {// ProgressDialog showDialog (PROGRESS_DIALOG);}/* executes time-consuming background computing tasks. You can call publishProgress to update the real-time task progress. * // @ Override protected Integer doInBackground (ArrayList
  
   
... Datas) {ArrayList
   
    
Data = datas [0]; for (int I = 0; I <8; I ++) {data. add ("ListItem");} return STATE_FINISH;}/* after doInBackground is executed, the onPostExecute method will be called by the UI thread, * The background computing result is passed to the UI thread through this method. * // @ Override protected void onPostExecute (Integer result) {int state = result. intValue (); switch (state) {case STATE_FINISH: dismissDialog (PROGRESS_DIALOG); Toast. makeText (getApplicationContext (), "Loading completed! ", Toast. LENGTH_LONG). show (); adapter = new ArrayAdapter
    
     
(GetApplicationContext (), android. r. layout. simple_list_item_1, data); setListAdapter (adapter); break; case STATE_ERROR: dismissDialog (PROGRESS_DIALOG); Toast. makeText (getApplicationContext (), "An error occurred during the processing! ", Toast. LENGTH_LONG). show (); adapter = new ArrayAdapter
     
      
(GetApplicationContext (), android. R. layout. simple_list_item_1, data); setListAdapter (adapter); break; default :}}
     
    
   
  
 

Android also provides a tool class: AsyncTask. It makes the use of the UI thread very simple. It makes it easier to create long-running tasks that need to interact with the user interface, without the need to use threads and Handler.

1) subclass AsyncTask2) implement one or more of the following methods defined in AsyncTask before onPreExecute () starts the preparation work; doInBackground (Params ...) start to execute background processing. You can call publishProgress to update the real-time task Progress. onProgressUpdate (Progress ...) after the publishProgress method is called, the UI thread calls this method to display the progress of the task on the interface, for example, through a progress bar. OnPostExecute (Result) after the operation is completed, the Result is sent to the UI thread. None of the four methods can be called manually. Besides doInBackground (Params ...) the other three methods are called by the UI thread, so the requirements are as follows: 1) The AsyncTask instance must be created in the UI thread; 2) the AsyncTask.exe cute method must be called in the UI thread. Note that the task can only be executed once. Otherwise, exceptions may occur during multiple calls. In addition, you cannot manually stop it. Pay attention to this to see if it meets your needs! During usage, it is found that the parameter settings of the AsyncTask constructor must be clear: AsyncTask Params corresponds to the doInBackground (Params...) parameter type. New asynctask(cmd.exe cute (Params... params), that is, the incoming Params data. You can execute (data) to transmit one data, or execute (data1, data2, data3) data. Progress corresponds to the parameter type of onProgressUpdate (Progress...); Result corresponds to the parameter type of onPostExecute (Result. If none of the preceding parameter types need to be specified, use Void. Note that it is not void. For more information, see the example above or the example in the API Doc.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.