In an in-depth analysis of the message cycle of Android handler
Handler is used to manipulate message queues within threads, so handler can be used to communicate with the ITC in a way that is more secure and efficient, and can greatly reduce the annoyance of synchronization, even without syncrhonized.
Inter-thread communication ITC
Normally the function call stack survives within the same thread, and you want to switch the execution logic to another thread, you can create a new thread, and then start (). Another approach is to use ITC, also known as Message Queuing, where a thread needs to deliver execution logic to another thread, sending a message to the message queue of the other, and the function ends when the message is sent, and the call stack stops. When there is a message in the message queue, the thread is awakened to execute the processing message, which transfers the execution logic from one thread to another. This realizes the communication between the threads of the ITC, and the communication IPC has a very similar idea.
It is common practice to create a handler on the main thread and then use this handler to communicate with the main thread in the new threads. Because the message queue for the main thread is already built, you can create the handler directly, and the new thread will be used directly.
In some cases, it is necessary to communicate between multithreading, which is to create MessageQueue and handler for each thread, as long as the thread can access the handler of other threads to communicate with it.
To create the handler correctly, because handler is bound to the thread, be aware when initializing handler:
If you assign the Looper object new Handler (Looper) to Handler, the Handler is bound to the thread where the Looper object is located, and the message processing callback for Handler executes on that thread.
If the Looper object is not specified when the thread is created, the handler is bound to the thread that created the handler, and the message callback processing executes in that thread, so as in the following example, if you write:
Private class Cookserver extends Thread {
Private Handler Mhandler = new Handler () {
public void Handlemessage (msg) {
....
}
};
Then, this mhandler will be bound to the thread that created this cookerserver, and Handlemessage will run in it. Obviously, if the main thread calls new Cookserver (), then Mhandler is actually running in the main thread. The correct wording should be:
Private class Cookserver extends Thread {
public void Run () {
Looper.prepare ();
//or New Handler (Looper.mylooper ())
private Handler Mhandler = new Handler () {
public void Handlemessage ( Message msg) {
.....
}
};
Handlerthread
If you want to use Message Queuing and the Handler,android API in a thread that already has encapsulated a class Handlerthread, this class has done the Looper initialization work, all you need to do is rewrite its onlooperprepared () method in which to create the handler:
Private class Deliverserver extends Handlerthread {
Private Handler Mhandler;
Public Deliverserver (String name) {
Super (name);
}
@Override
public void onlooperprepared () {
Mhandler = new Handler (Getlooper ()) {
public void Handlemessage (msg) {
.....
}
};
}
}
Instance
This example simulates a network ordering system, the customer clicks on "Submit order" to produce a PO, the main thread is responsible for the collection of orders, and then to Cookserver to make, cookserver in the production will be handed over to the deliverserver to the customer to deliver food , so that an order is completed, and Cookserver and Deliverserver will update the status.
code as follows:
/**
* Attach an Handler to a Thread:
* If You are specify Looper object to Handler, i.e. new Handler (Looper), then the Handler is attached to the thread owning
* The Looper object, in which Handlemessage () is executed.
* If You don't specify the Looper object, then the handler is attached to the thread calling new handler (), in which
* Handlemessage () is executed.
* In this example, for class cookserver or Deliverserver, if you write this way:
* Private class Cookserver extends Thread {
Private Handler Mhandler;
Private Looper Mlooper;
Public Cookserver () {
Mhandler = new Handler () {
@Override
public void Handlemessage (msg) {
....
}
Start ();
}
* Then Mhandler is attached to thread calling new Cookserver (), which are the main thread, so Mhandler.handlemessage ()
* is executed in main thread.
* To attach Mhandler-own thread, you are must put it in run (), or after the Mlooper is created. For our example, providing
* Mlooper or not won ' t matter, because new Handler () are called in Run (), which are in a new thread.
*/
public class Handleritcdemo extends Listactivity {
private static final int cooking_started = 1;
private static final int cooking_done = 2;
private static final int delivering_started = 3;
private static final int order_done = 4;
Private ListView Mlistview;
private static final string[] Mfoods = new string[] {
"Cubake",
"Donut",
"Eclaire",
"Gingerbread",
"Honeycomb",
"Ice Cream Sanwitch",
"Jelly Bean",
};
Private arraylist<string> morderlist;
Private TextView Mgeneralstatus;
Private Button Msubmitorder;
private static Random Mrandomer = new Random (47);
private int mordercount;
private int mcookingcount;
private int mdeliveringcount;
private int mdonecount;
Private Handler Mmainhandler = new Handler () {
@Override
public void Handlemessage (msg) {
Switch (msg.what) {
Case cooking_started:
mcookingcount++;
Break
Case Cooking_done:
mcookingcount--;
Break
Case delivering_started:
mdeliveringcount++;
Break
Case Order_done:
mdeliveringcount--;
mdonecount++;
Default
Break
}
Mgeneralstatus.settext (Makestatuslabel ());
}
};
Private Cookserver Mcookserver;
Private Deliverserver Mdeliverserver;
@Override
protected void OnDestroy () {
Super.ondestroy ();
if (mcookserver!= null) {
Mcookserver.exit ();
Mcookserver = null;
}
if (mdeliverserver!= null) {
Mdeliverserver.exit ();
Mdeliverserver = null;
}
}
@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Mlistview = Getlistview ();
Morderlist = new arraylist<string> ();
Mgeneralstatus = new TextView (Getapplication ());
Mgeneralstatus.settext (Makestatuslabel ());
Msubmitorder = new Button (Getapplication ());
Msubmitorder.settext ("Submit order");
Msubmitorder.setonclicklistener (New View.onclicklistener () {
public void OnClick (View v) {
String order = Mfoods[mrandomer.nextint (mfoods.length)];
Morderlist.add (order);
Mordercount = Morderlist.size ();
Mgeneralstatus.settext (Makestatuslabel ());
Setadapter ();
Mcookserver.cook (order);
}
});
Mlistview.addheaderview (Mgeneralstatus);
Mlistview.addfooterview (Msubmitorder);
Setadapter ();
Mcookserver = new Cookserver ();
Mdeliverserver = new Deliverserver ("Deliver server");
}
Private String Makestatuslabel () {
StringBuilder sb = new StringBuilder ();
Sb.append ("total:");
Sb.append (Mordercount);
Sb.append ("Cooking:");
Sb.append (Mcookingcount);
Sb.append ("Delivering:");
Sb.append (Mdeliveringcount);
Sb.append ("Done:");
Sb.append (Mdonecount);
return sb.tostring ();
}
private void Setadapter () {
Final ListAdapter adapter = new Arrayadapter<string> (Getapplication (), Android. R.layout.simple_list_item_1, morderlist);
Setlistadapter (adapter);
}
Private class Cookserver extends Thread {
Private Handler Mhandler;
Private Looper Mlooper;
Public Cookserver () {
Start ();
}
@Override
public void Run () {
Looper.prepare ();
Mlooper = Looper.mylooper ();
Mhandler = new Handler (Mlooper, New Handler.callback () {
public boolean handlemessage (msg) {
New Cooker ((String) msg.obj);
return true;
}
});
Looper.loop ();
}
public void Cook (String order) {
if (Mlooper = null | | mhandler = NULL) {
Return
}
Message msg = Message.obtain ();
Msg.obj = order;
Mhandler.sendmessage (msg);
}
public void exit () {
if (mlooper!= null) {
Mlooper.quit ();
Mhandler = null;
Mlooper = null;
}
}
}
Private class Cooker extends Thread {
private String order;
Public Cooker (String order) {
This.order = order;
Start ();
}
@Override
public void Run () {
Mmainhandler.sendemptymessage (cooking_started);
Systemclock.sleep (Mrandomer.nextint (50000));
Mdeliverserver.deliver (order);
Mmainhandler.sendemptymessage (Cooking_done);
}
}
Private class Deliverserver extends Handlerthread {
Private Handler Mhandler;
Public Deliverserver (String name) {
Super (name);
Start ();
}
@Override
protected void onlooperprepared () {
Super.onlooperprepared ();
Mhandler = new Handler (Getlooper (), new Handler.callback () {
public boolean handlemessage (msg) {
New Deliver ((String) msg.obj);
return true;
}
});
}
public void Deliver (String order) {
if (Mhandler = null | | getlooper () = null) {
Return
}
Message msg = Message.obtain ();
Msg.obj = order;
Mhandler.sendmessage (msg);
}
public void exit () {
Quit ();
Mhandler = null;
}
}
Private class Deliver extends Thread {
private String order;
Public Deliver (String order) {
This.order = order;
Start ();
}
@Override
public void Run () {
Mmainhandler.sendemptymessage (delivering_started);
Systemclock.sleep (Mrandomer.nextint (50000));
Mmainhandler.sendemptymessage (Order_done);
}
}
}