I think there has been a lot of discussion about this topic. Today is a study to summarize it.
In the design idea of Android, in order to ensure the user smooth operation experience. Some time-consuming tasks cannot be run in the UI thread, such as accessing the network. So we have to re-open a background thread to run these tasks. However, these tasks often end up needing to access and control the UI controls directly or indirectly. For example, access to the network to obtain data, and then need to display these data processing. The above-mentioned situation arises. This is a normal phenomenon, but Android rules that no other thread can access and manipulate the UI controls other than the UI thread. In order to solve this problem, it leads to our topic today. How background threads in Android interact with the UI thread.
As far as I know, Android provides the following methods to enable background threads to interact with the UI thread.
1, Handler
2, Activity.runonuithread (Runnable)
3, View.post (Runnable)
4, view.postdelayed (Runnabe,long)
5, Asynctask
Method One: Handler
Handler is a tool that is specifically used to pass information classes between threads in Android.
To make it clear that handler is very simple to use, but I'll talk a little bit more about the handler mechanism.
In order to allow handler to pass messages between threads, we also need to use several classes. They are looper,messagequeue,message.
The looper here is not the Hollywood blockbuster of the previous period, his main function is to run a message ring for a particular single thread. One thread corresponds to a looper. The same looper corresponds to a thread. This is called a specific single. In general, when a thread is created, he will not produce his particular single looper (the main thread is a special case). So we need to manually associate a looper with the line threads. Its method simply calls Looper.prepare in the thread that requires the associated looper. We then call Looper.loop to start Looper.
Having said so many looper things, what is the use of this looper? In fact, as we have said before, he is running a message ring for the thread. Specifically, when we associate a particular single looper with a thread, Looper produces a MessageQueue at the same time. He is a message queue, and Looper will keep extracting messages from Messagequee, which is the message. The thread then makes the appropriate action based on the content in the message.
So where does the message in MessageQueue come from? That will be the mention of handler. When we create handler, we need to bind to a specific looper. By handler we can then pass the message to a specific looper and then pass it on to a particular thread. Here, Looper and handler are not one by one corresponding. A looper can correspond to multiple handler, and a handler can only correspond to one looper (suddenly think of polygamy, hehe). In addition, the bindings for handler and Looper are implemented at the time of building the handler, specifically querying the handler constructor.
After we create the handler and bind to the corresponding looper, we can pass the message. We just need to call handler's SendMessage function and pass the message as a parameter to the appropriate thread. The message will then be stuffed into the looper MessageQueue. It is then removed by the Looper to the threading process.
To add a message here, although we can create a new message ourselves, it is more recommended to call handler's Obtainmessage method to get a message. The purpose of this method is to remove a message from the system's messaging pool, which avoids the wasted resources of message creation and destruction (which is a reusable green lift).
It suddenly dawned on me that there was something important that was not mentioned, that is, how the thread responded after receiving the message from Looper. In fact, what kind of response the thread needs to make is written in the Handlemessage refactoring method of our custom handler class. That's what I said before. Create handler and bind Looper.
Well, that might be a little messy, so let's summarize the method of transmitting information using handler.
Assuming a thread is going to pass information to the B thread, all we need to do is
1. Call Looper.prepare and looper.loop in the B thread. (not required for main thread)
2, write the handler class, rewrite the Handlemessage method.
3. Create an instance of the handler class and bind the Looper
4. Call handler's Sentmessage method to send the message.
Here, we want to handler the operating mechanism I should be elaborated almost, and finally attached a piece of code for everyone to refer to.
1 public class Myhandleractivity extends Activity {2 TextView TextView; 3 MyHandler MyHandler; 4 5 Prot ected void OnCreate (Bundle savedinstancestate) {6 super.oncreate (savedinstancestate); 7 Setcontentview ( R.layout.handlertest); 8 9//implement create Handler and bind to Looper. There is no correlation between looper and//threads because the main thread was created at the beginning of the Looper10 Myhandler=myhandler (Myhandleractivitythis.getmainlooper ()) ; TextView = (TextView) Findviewbyid (R.id.textview); MyThread m = new MyThread (); 14 New Thread (M). Start ();}16-Class MyHandler extends Handler {public MyHandler () {20 }21 MyHandler (Looper l) {24}25 26//must override this method for handling m Essage27 @Override28 public void Handlemessage (Message msg) {29//Here for update UI30 Bundle B = msg.getdata (); String color = b.getstring ("color"); 32 MyHandlerActivity.this.textView.setText (color)}34}35 class MyThread implements Runnab Le {PNs public void run () {38//Remove a message39 message msg = Myhandler.obtainmessage from the messaging pool ();//bundle is the data in the message bundle B = new Bundle (), b.putstring ("Color", "my"); Msg.setdata (b); 44//Transmit Data myhandler.sendmessage (msg); Send message to Handler, update UI46}47}
Method Two: Activity.runonuithread (Runnable)
This method is quite simple, and all we have to do is the following steps
1, write the background thread, this time you can call the UI control directly
2. Create an instance of a background thread
3. Invoke the Runonuithread method of the activity that corresponds to the UI thread, passing the background thread instance as a parameter.
Note: You do not need to call the Start method of a background thread
Method Three: View.post (Runnable)
The method and method two are basically the same, except that the UI controls that can be manipulated in a background thread are limited and can only be the specified UI control view. Methods are as follows
1, write a background thread, this time you can call the UI control directly, but the UI control can only be view
2. Create an instance of a background thread
3. Call the Post method of the UI control view to pass in the background thread instance as a parameter.
Method Four: view.postdelayed (Runnabe,long)
The method is a supplement to method three, which is used to establish how long the background process runs after
Method Five: Asynctask
Asynctask is a tool that is designed to handle background processes and UI threads. With Asynctask, we can easily communicate between the background thread and the UI thread.
So how does Asynctask work?
Asynctask has 3 key parameters
1. Params
2, Progress
3. Result
The params is the parameter required by the background thread. When the background thread is doing the job, he needs the outside to give it the necessary parameters, as if it were a background process for downloading the picture, and the parameters he needs are the pictures.
Progress is the progress of the background thread processing job. Still the above example says, is the download picture this task accomplished how much, is 20% or 60%. This number is provided by progress.
Results are the result of running the background thread, which is the information that needs to be submitted to the UI thread. In the example above, it is the downloaded picture.
The Asynctask also has 4 important callback methods.
1, OnPreExecute
2, Doinbackground
3, Onprogressupdate
4, OnPostExecute
OnPreExecute runs on the UI thread, and the main purpose is to prepare for the running of the background thread. When he finishes running, he will call the Doinbackground method.
Doinbackground runs on a background thread, and he is responsible for running the task. He has a parametric params and returns result. The Publishprogress method needs to be called in the Doinbackground method in order to be able to update the progress of the job completion in the background thread's run. The method has parameter progress. This method allows you to update the progress data. Then when the Publishprogress method is called, he calls the Onprogressupdate method to update the progress.
Onprogressupdate runs on the UI thread and is primarily intended to update UI controls that display progress in the UI thread. He has progress parameters. After calling Publishprogress in Doinbackground, the Onprogressupdate method is automatically tuned
OnPostExecute runs on the UI thread, and when the Doinbackground method finishes running, he calls the OnPostExecute method and passes in result. In the OnPostExecute method, result can be updated to the UI control.
Understand the above 3 parameters and 4 methods, all you have to do is
1, write a class that inherits Asynctask, and declare the type of 3 parameters, write the contents of 4 callback methods.
2. Then create the class in the UI thread (must be created in the UI thread).
3. Finally call the Execute method of Asynctask, passing in the Parmas parameter (also must be called in the UI thread).
That's it.
Another notable 2 point is that you should never call the four callback methods directly. There is a Asynctask instance can only be executed once, otherwise it will be wrong oh.
The above is the basic usage of asynctask, please refer to the official Android documentation for more detailed information. Finally, we enclose a piece of code for your reference.
1 private class Downloadfilestask extends Asynctask<url, Integer, long> 2//here declares the params, Progress, and result parameters of type 3 { 4//Because there is no need to use the OnPreExecute callback method, so there is no way to join the method 5 6//Background thread is more URL to download data 7 protected Long doinbackground (URL ... URLs) {8 int count = Urls.length;//urls is an array, more than one download link 9 long totalsize = 0;//downloaded data for (int i = 0; I < count; i++) {One//download is a class for download, and asynctask is irrelevant, you can ignore his implementation of the TotalSize + = Downloader.downloadfile (URLs [i]); Publishprogress ((int) ((I/(float) count) * 100))//Update download progress//Escape early if Cancel () is Called15 if (iscancelled ()) break;16}17 return totalsize;18}19 20//Update download Progress 21 protected void Onprogressupdate (Integer ... progress) {setprogresspercent (progress[0]); 23}24 25 Update downloaded data to UI thread protected void OnPostExecute (Long result) {ShowDialog ("downloaded" + result + "bytes"); 28}29}30
With this class above, all you have to do is create an instance in the UI thread and invoke the Execute method, passing in the URL parameter.
There are advantages to all 5 of these methods. But the fundamental, in fact, the following four methods are based on the handler method of packaging. In the general case, the latter four seems to be more recommendable. However, when the situation is more complex, it is recommended to use handler.