In 《
In-depth analysis of message loops in Android HandlerHandler is used to operate the Message Queue inside the thread, so Handler can be used to communicate with ITC between threads. This method is safer and more efficient, which can greatly reduce synchronization troubles, you don't even need syncrhonized.
Inter-thread communication ITC
Under normal circumstances, the function call stack will survive in the same Thread. to switch the execution logic to other threads, you can create a new Thread and start (). Another method is to use ITC, or message queue. When the thread needs to submit the execution logic to another thread, it sends a message to the Message Queue of another thread, after a message is sent, the function ends and the call stack stops. When there is a message in the message queue, the thread will be awakened to execute message processing, so that the execution logic is transferred from one thread to another. This achieves the communication between threads (ITC), which is similar to the idea of Inter-Communication (IPC.
The common practice is to create a Handler in the main thread, and then use this Handler to communicate with the main thread in the new thread. Because the message queue of the main thread has been created, you can directly create Handler, and the newly created thread can be directly used.
In some cases, communication between multiple threads is required. In this case, MessageQueue and Handler must be created for each thread. As long as the thread can access the Handler of other threads, it can communicate with them.
To correctly create a Handler, because the Handler must be bound to the thread, you must note the following when initializing the Handler:
If a logoff object new Handler is specified for Handler, the Handler is bound to the thread where the logoff object is located, and the Handler Message Processing callback is executed in that thread.
If the logoff object is not specified during thread creation, the Handler is bound to the thread where the Handler is created, and the message callback processing will be executed in that thread, so as shown in the following example, write the following statement:Copy codeThe Code is as follows: private class CookServer extends Thread {
Private Handler mHandler = new Handler (){
Public void handleMessage (Message msg ){
....
}
};
Then, the mHandler will be bound to the thread that created the CookerServer, And the handleMessage will also run in it. Obviously, if the main thread calls new CookServer (), mHandler actually runs in the main thread. The correct statement should be:Copy codeThe Code is as follows: private class CookServer extends Thread {
Public void run (){
Logoff. prepare ();
// Or new Handler (lorule. mylorule ())
Private Handler mHandler = new Handler (){
Public void handleMessage (Message msg ){
....
}
};
HandlerThread
If you want to use the message queue and Handler in a thread, the Android API already has a encapsulated HandlerThread class. This class has completed logoff initialization, all you need to do is override its onLooperPrepared () method and create Handler in it:Copy codeThe Code is as follows: 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 (Message msg ){
.....
}
};
}
}
Instance
This instance simulates an online ordering system. The customer clicks "Submit order" to generate an order. The main thread collects the order and submits it to the CookServer for production, after the CookServer is created, it will be handed over to the DeliverServer to ship the food to the customer. At this point, an order is completed, and both CookServer and DeliverServer will update the status.
Copy codeThe Code is as follows :/**
* How to attach an Handler to a Thread:
* If you specify loginobject to Handler, I. e. new Handler (logint), then the handler is attached to the thread owning
* The loginobject, in which handleMessage () is executed.
* If you do not specify the loginobject, 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 loopdomainmlow.gov.cn;
Public CookServer (){
MHandler = new Handler (){
@ Override
Public void handleMessage (Message msg ){
....
}
Start ();
}
* Then mHandler is attached to thread calling new CookServer (), which is the main thread, so mHandler. handleMessage () will
* Be executed in main thread.
* To attach mHandler to its own thread, you must put it in run (), or after mLooper is created. For our example, providing
* MLooper or not won't matter, because new Handler () is called in run (), which is 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 (Message 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 loopdomainmlow.gov.cn;
Public CookServer (){
Start ();
}
@ Override
Public void run (){
Logoff. prepare ();
Mlogoff = logoff. mylogoff ();
MHandler = new Handler (mloler, new Handler. Callback (){
Public boolean handleMessage (Message msg ){
New Cooker (String) msg. obj );
Return true;
}
});
Logoff. loop ();
}
Public void cook (String order ){
If (mloiter = null | mHandler = null ){
Return;
}
Message msg = Message. obtain ();
Msg. obj = order;
MHandler. sendMessage (msg );
}
Public void exit (){
If (mlogoff! = Null ){
Mloit. quit ();
MHandler = null;
Mlogoff = 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 (Message 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 );
}
}
}