When the Android application is running, a main thread is created (also known as the UI thread), which is primarily responsible for handling UI-related events, and because Android uses the UI single-threaded model, the UI elements can only be manipulated in the main thread, if the UI is directly manipulated on non-UI threads. will be an error, in addition, for the operation of a large number of operations and IO operations, we need a new thread to handle this work, so as not to block the UI thread, the child thread and the main thread is how to communicate? In this case, the message loop mechanism (Looper) is used to process the handler.
first, the basic concept
Looper : Each thread can produce a looper, and the Message,looper object used to manage the thread creates a MESSGAEQUEUE data structure to hold the message.
Handler : The object that communicates with Looper, can push message or Runnable object to Messgaequeue, also can get message from MessageQueue.
To view its constructors:
Handler ()
Default constructor Associates this handler with the queue for the current thread.//if you do not specify the Looper parameter, the Looper created
Handler (Looper Looper)
Use the provided queue instead of the default one.//create handler using the specified Looper object
Thread A's handler object reference can be passed to other threads, allowing other threads such as B or C to send messages to thread A.
Thread A's message in the queue, only the object that the thread a belongs to can handle.
Note: There is no global MessageQueue in Android, and different processes (or APK) cannot exchange messages through MessageQueue.
handler Basic way of communication through message
Use looper.mylooper to get the Looper object for the current thread.
Use Mhandler = new Handler (Looper.mylooper ()); The handler object that is used to process the current thread can be generated.
Use Mhandler = new Handler (Looper.getmainlooper ()); The handler object that is used to process the main thread is created.
When you use Handler to pass a message object into a message object, the main fields in the Message object are as follows:
The message object can be obtained through the constructor of the message class, but Google recommends using the Message.obtain () method, which returns a reusable messgae instance from the global object pool, as explained in the API:
Message ()
Constructor (But the preferred-to-get-a Message is-to-call Message.obtain ()).
Handler when a message is sent, you can either specify that the message is processed immediately after it is accepted, or you can specify that it be processed after a certain time interval, such as sendmessagedelayed (Message msg, long Delaymillis), refer to the API.
After the handler message is sent out, it is processed by the Handlemessage (Message msg) method.
Note: On Android, a new thread is created, and it does not automatically establish its message loop by calling Looper.prepare () to establish a MessageQueue for that thread, and then call Looper.loop () to cycle through the messages.
The following examples illustrate:
Define two buttons and one textview in Main.xml
public class handlertestactivity extends activity implements onclicklistener{ public TextView tv; private myThread myT; Button bt1, bt2; @Override Public void oncreate (bundle savedinstancestate) { super.oncreate (savedinstancestate); setcontentview ( R.layout.main); bt1 = (Button) findViewById (R.ID.A); bt2 = (Button) Findviewbyid (r.id.b); tv = (TextView) Findviewbyid (r.id.tv); bt1.setid (1);//Set the ID for two buttons, which is used to determine which button was pressed after bt2.setid (2);  &NBsp; bt1.setonclicklistener (this);//Add Listener bt2.setonclicklistener (this); } @Override public void onclick (VIEW V) { switch (V.getid ()) {//Key event response, if the first key will start a new thread case 1: myt = new mythread (); myt.start (); break; case 2: finish (); break; default: break; } } class myThread extends Thread { private EHandler mHandler; Public void run () { Looper myLooper, mainLooper; mylooper = looper.mylooper ();//Get looper of current thread mainlooper = looper.getmainlooper ();//Get UI thread looper String obj; if (mylooper == null) { // Determines whether the current thread has a message loop Looper &nbsP; mhandler = new ehandler (Mainlooper); obj = "current thread has no looper!"; /current Looper is empty, Ehandler with Mainlooper object construction } else { Mhandler = new ehandler (mylooper);//current looper is not empty, Ehandler is constructed with the Looper object of the current thread obj = "This is from current thread. "; } mhandler.removemessages (0);//clear contents of message Queue &Nbsp; message m = mhandler.obtainmessage (1, 1, 1, obj); mhandler.sendmessage ( m);//Send Message } } class EHandler extends Handler { public ehandler (Looper looper) { super (Looper); } @Override public void Handlemessage (message msg) { //message processing functions tv.settext (String) msg.obj);//Set TextView content } }}
After the program runs, click the Testlooper button, the TextView output is as follows, the newly created line thread Looper is empty, it also shows that the newly created thread does not create a message Looper itself.
To modify the Mythread class:
Class MyThread extends Thread {private Ehandler mhandler; public void Run () {Looper mylooper, mainlooper; Looper.prepare (); Mylooper = Looper.mylooper (); Mainlooper = Looper.getmainlooper (); ........ mhandler.sendmessage (m); Looper.loop (); }}
Looper.prepare creates a message Looper,looper.loop () for the current thread to turn on the messages loop. Is this modification OK?
The answer is NO! The runtime Logcat throws a calledfromwrongthreadexception exception error, which is prompted as follows:
This means " only the thread that originally created this view level can modify its view ", in this case the TextView is created in the UI thread (the main thread), so the mythread thread cannot modify its display!
The general practice is to get the handler object of the mainline thread in the sub-thread, and then send the message to the main thread's message queue for communication through the object.
If a child thread wants to modify the UI of the main thread, it can refer to the previous code by sending a message to the main thread's messages queue, the main line Cheng judgment processing, and then to the UI by line operation.
third, the basic way of handler through runnable communication
We can communicate between threads via the handler post method, which is described in the API for the POST method:
Public Final Boolean post (Runnable R)
Causes the Runnable R to is added to the message queue. The runnable'll be run on the thread to which this handler is attached.
The Post method will schedule the Runnable object to run at some point in the main thread, but will not open a new thread, and the verification code is as follows:
Public class handlertestactivity extends activity { private Handler handlerTest; Runnable runnableTest = new Runnable () { public void run () { string runid = string.valueof ( Thread.CurrentThread (). GetId ());//output runnable thread ID number   LOG.V ("Debug", RunID); } }; @Override public void oncreate (bundle savedinstancestate) { super.oncreate (savedInstanceState); setcontentview (R.layout.main); handlertest = new handleR (); string mainid = string.valueof ( Thread.CurrentThread (). GetId ());         LOG.V ("Debug", Mainid);// The output main thread ID number handlertest.post (runnabletest); }}
The output in Logcat is as follows:
The description simply puts the run method in the runnable in the UI thread and does not create a new thread
So we can add runnable to the MessageQueue of the main thread in the child thread, and the main thread will call the Runnable method, which can update the main thread UI in this method.
Modify the previous code to read as follows:
Public class handlertestactivity extends activity { private handler handlertest; private textview tv; @ Override public void oncreate (bundle savedinstancestate) { super.oncreate (savedinstancestate); setcontentview (r.layout.main); tv = (TextView) Findviewbyid (r.id.tv)//textview initialized to null Handlertest = new handler (); mythread myt = new mythread (); myt.start ();//Open sub-thread } class myThread extends Thread{ public vOid run () { handlertest.post ( Runnabletest);//child thread will runnable join message queue } } runnable runnabletest = new runnable () { public void run () { tv.settext ("This information is output by child threads!") "); } };}
The equivalent of calling the Runnalbe run method in the main thread, changing the TextView ui!
Communication mechanism between Android threads