天天看點

Handler,Looper,MessageQueue,Message總結

轉載部分來自: http://gundumw100.iteye.com/blog/858233

轉載部分對于應用層非常簡潔明了

原創部分是基于Android4.4源代碼,有什麼錯誤或不足,歡迎指正

轉載部分:

一、幾個關鍵概念 

1、MessageQueue:是一種 資料 結構,見名知義,就是一個消息隊列,存放消息的地方。每一個線程最多隻可以擁有一個MessageQueue資料結構。 

建立一個線程的時候,并不會自動 建立其MessageQueue。通常使用一個Looper對象對該線程的MessageQueue進行管理。主線程建立時,會建立一個預設的Looper對象,而Looper對象的建立,将自動建立一個Message Queue。其他非主線程,不會自動建立Looper,要需要的時候,通過調用prepare函數來實作。 

2、Message:消息對象,Message Queue中的存放的對象。一個Message Queue中包含多個Message。 

Message執行個體對象的取得,通常使用Message類裡的靜态方法obtain(),該方法有多個重載版本可供選擇;它的建立并不一定是直接建立一個新的執行個體,而是先從Message Pool(消息池)中看有沒有可用的Message執行個體,存在則直接取出傳回這個執行個體。如果Message Pool中沒有可用的Message執行個體,則才用給定的參數建立一個Message對象。調用removeMessages()時,将Message從Message Queue中删除,同時放入到Message Pool中。除了上面這種方式,也可以通過Handler對象的obtainMessage()擷取 一個Message執行個體。 

3、Looper: 

是MessageQueue的管理者。每一個MessageQueue都不能脫離Looper而存在,Looper對象的建立是通過prepare函數來實作的。同時每一個Looper對象和一個線程關聯。通過調用Looper.myLooper()可以獲得目前線程的Looper對象 

建立一個Looper對象時,會同時建立一個MessageQueue對象。除了主線程有預設的Looper,其他線程預設是沒有MessageQueue對象的,是以,不能接受Message。如需要接受,自己定義 一個Looper對象(通過prepare函數),這樣該線程就有了自己的Looper對象和MessageQueue資料結構了。 

Looper從MessageQueue中取出Message然後,交由Handler的handleMessage進行處理。處理完成後,調用Message.recycle()将其放入Message Pool中。 

4、Handler: 

消息的處理者,handler 負責将需要傳遞的資訊封裝成Message,通過調用handler 對象的obtainMessage()來實作; 

将消息傳遞給Looper,這是通過handler 對象的sendMessage()來實作的。繼而由Looper将Message放入MessageQueue中。 

當Looper對象看到MessageQueue中含有Message,就将其廣播出去。該handler 對象收到該消息後,調用相應的handler 對象的handleMessage()方法對其進行處理。 

二、線程之間的消息如何進行傳遞 

1、主線程給自己發送Message 

Java代碼  

Handler,Looper,MessageQueue,Message總結
  1. package test.message;   
  2. import android .app .Activity;  
  3. import android.os.Bundle;  
  4. import android.os.Handler;  
  5. import android.os.Looper;  
  6. import android.os.Message;  
  7. import android.view.View ;  
  8. import android.widget.Button;  
  9. import android.widget.TextView ;  
  10. public class MainActivity extends Activity {   
  11.     private Button btnTest;  
  12.     private TextView textView;  
  13.     private Handler handler ;  
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.main);  
  18.         btnTest = (Button)this.findViewById(R.id.btn_01);  
  19.         textView = (TextView)this.findViewById(R.id.view_01);  
  20.         btnTest.setOnClickListener(new View.OnClickListener() {  
  21.             @Override  
  22.             public void onClick(View arg0) {  
  23.                 Looper looper = Looper.getMainLooper(); //主線程的Looper對象  
  24.                 //這裡以主線程的Looper對象建立了handler ,  
  25.                 //是以,這個handler 發送的Message會被傳遞給主線程的MessageQueue。  
  26.                 handler = new MyHandler(looper);  
  27.                 handler .removeMessages(0);  
  28.                 //建構Message對象  
  29.                 //第一個參數:是自己指定的message代号,友善在handler 選擇性地接收  
  30.                 //第二三個參數沒有什麼意義  
  31.                 //第四個參數需要封裝的對象  
  32.                 Message msg = handler .obtainMessage(1,1,1,"主線程發消息了");  
  33.                 handler .sendMessage(msg); //發送消息  
  34.             }  
  35.         });  
  36.     }  
  37.     class MyHandler extends Handler{  
  38.         public MyHandler(Looper looper){  
  39.             super(looper);  
  40.         }  
  41.         public void handleMessage(Message msg){  
  42.             super.handleMessage(msg);  
  43.             textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);  
  44.         }  
  45.     }  
  46. }  

2、其他線程給主線程發送Message 

Java代碼  

Handler,Looper,MessageQueue,Message總結
  1. package test.message;   
  2. import android.app.Activity;   
  3. import android.os.Bundle;  
  4. import android.os.Handler;  
  5. import android.os.Looper;  
  6. import android.os.Message;  
  7. import android.view.View;  
  8. import android.widget.Button;  
  9. import android.widget.TextView;  
  10. public class MainActivity extends Activity {   
  11.     private Button btnTest;  
  12.     private TextView textView;  
  13.     private Handler handler ;  
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.main);  
  18.         btnTest = (Button)this.findViewById(R.id.btn_01);  
  19.         textView = (TextView)this.findViewById(R.id.view_01);  
  20.         btnTest.setOnClickListener(new View.OnClickListener() {  
  21.             @Override  
  22.             public void onClick(View arg0) {  
  23.                 //可以看出這裡啟動了一個線程來操作消息的封裝和發送的工作  
  24.                 //這樣原來主線程的發送就變成了其他線程的發送,簡單吧?呵呵  
  25.                 new MyThread().start();      
  26.             }  
  27.         });  
  28.     }  
  29.     class MyHandler extends Handler{  
  30.         public MyHandler(Looper looper){  
  31.             super(looper);  
  32.         }  
  33.         public void handleMessage(Message msg){  
  34.             super.handleMessage(msg);  
  35.             textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);  
  36.         }  
  37.     }  
  38.     //加了一個線程類  
  39.     class MyThread extends Thread{  
  40.         public void run(){  
  41.             Looper looper = Looper.getMainLooper(); //主線程的Looper對象  
  42.             //這裡以主線程的Looper對象建立了handler ,  
  43.             //是以,這個handler 發送的Message會被傳遞給主線程的MessageQueue。  
  44.             handler = new MyHandler(looper);  
  45.             //建構Message對象  
  46.             //第一個參數:是自己指定的message代号,友善在handler 選擇性地接收  
  47.             //第二三個參數沒有什麼意義  
  48.             //第四個參數需要封裝的對象  
  49.             Message msg = handler .obtainMessage(1,1,1,"其他線程發消息了");  
  50.             handler .sendMessage(msg); //發送消息              
  51.         }  
  52.     }  
  53. }  

3、主線程給其他線程發送Message 

Java代碼  

Handler,Looper,MessageQueue,Message總結
  1. package test.message;   
  2. import android.app.Activity;   
  3. import android.os.Bundle;  
  4. import android.os.Handler;  
  5. import android.os.Looper;  
  6. import android.os.Message;  
  7. import android.view.View;  
  8. import android.widget.Button;  
  9. import android.widget.TextView;  
  10. public class MainActivity extends Activity {   
  11.     private Button btnTest;  
  12.     private TextView textView;  
  13.     private Handler handler ;  
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.main);  
  18.         btnTest = (Button)this.findViewById(R.id.btn_01);  
  19.         textView = (TextView)this.findViewById(R.id.view_01);  
  20.         //啟動線程  
  21.         new MyThread().start();      
  22.         btnTest.setOnClickListener(new View.OnClickListener() {  
  23.             @Override  
  24.             public void onClick(View arg0) {  
  25.                 //這裡handler 的執行個體化線上程中  
  26.                 //線程啟動的時候就已經執行個體化了  
  27.                 Message msg = handler .obtainMessage(1,1,1,"主線程發送的消息");  
  28.                 handler .sendMessage(msg);  
  29.             }  
  30.         });  
  31.     }  
  32.     class MyHandler extends Handler{  
  33.         public MyHandler(Looper looper){  
  34.             super(looper);  
  35.         }  
  36.         public void handleMessage(Message msg){  
  37.             super.handleMessage(msg);  
  38.             textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);  
  39.         }  
  40.     }  
  41.     class MyThread extends Thread{  
  42.         public void run(){  
  43.             Looper.prepare(); //建立該線程的Looper對象,用于接收消息  
  44.             //注意了:這裡的handler 是定義在主線程中的哦,呵呵,  
  45.             //前面看到直接使用了handler 對象,是不是在找,在什麼地方執行個體化的呢?  
  46.             //現在看到了吧???呵呵,開始的時候執行個體化不了,因為該線程的Looper對象  
  47.             //還不存在呢。現在可以執行個體化了  
  48.             //這裡Looper.myLooper()獲得的就是該線程的Looper對象了  
  49.             handler = new ThreadHandler(Looper.myLooper());  
  50.             //這個方法,有疑惑嗎?  
  51.             //其實就是一個循環,循環從MessageQueue中取消息。  
  52.             //不經常去看看,你怎麼知道你有新消息呢???  
  53.             Looper.loop();   
  54.         }  
  55.         //定義線程類中的消息處理類  
  56.         class ThreadHandler extends Handler{  
  57.             public ThreadHandler(Looper looper){  
  58.                 super(looper);  
  59.             }  
  60.             public void handleMessage(Message msg){  
  61.                 //這裡對該線程中的MessageQueue中的Message進行處理  
  62.                 //這裡我們再傳回給主線程一個消息  
  63.                 handler = new MyHandler(Looper.getMainLooper());  
  64.                 Message msg2 = handler .obtainMessage(1,1,1,"子線程收到:"+(String)msg.obj);  
  65.                 handler .sendMessage(msg2);  
  66.             }  
  67.         }  
  68.     }  
  69. }  

4、其他線程給自己發送Message 

Java代碼  

Handler,Looper,MessageQueue,Message總結
  1. package test.message;   
  2. import android.app.Activity;   
  3. import android.os.Bundle;  
  4. import android.os.Handler;  
  5. import android.os.Looper;  
  6. import android.os.Message;  
  7. import android.view.View;  
  8. import android.widget.Button;  
  9. import android.widget.TextView;  
  10. public class MainActivity extends Activity {   
  11.     private Button btnTest;  
  12.     private TextView textView;  
  13.     private Handler handler ;  
  14.     @Override  
  15.     public void onCreate(Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.main);  
  18.         btnTest = (Button)this.findViewById(R.id.btn_01);  
  19.         textView = (TextView)this.findViewById(R.id.view_01);  
  20.         btnTest.setOnClickListener(new View.OnClickListener() {  
  21.             @Override  
  22.             public void onClick(View arg0) {  
  23.                 //啟動線程  
  24.                 new MyThread().start();      
  25.             }  
  26.         });  
  27.     }  
  28.     class MyHandler extends Handler{  
  29.         public MyHandler(Looper looper){  
  30.             super(looper);  
  31.         }  
  32.         public void handleMessage(Message msg){  
  33.             super.handleMessage(msg);  
  34.             textView.setText((String)msg.obj);  
  35.         }  
  36.     }      
  37.     class MyThread extends Thread{  
  38.         public void run(){  
  39.             Looper.prepare(); //建立該線程的Looper對象  
  40.             //這裡Looper.myLooper()獲得的就是該線程的Looper對象了  
  41.             handler = new ThreadHandler(Looper.myLooper());  
  42.             Message msg = handler .obtainMessage(1,1,1,"我自己");  
  43.             handler .sendMessage(msg);  
  44.             Looper.loop();   
  45.         }  
  46.         //定義線程類中的消息處理類  
  47.         class ThreadHandler extends Handler{  
  48.             public ThreadHandler(Looper looper){  
  49.                 super(looper);  
  50.             }  
  51.             public void handleMessage(Message msg){  
  52.                 //這裡對該線程中的MessageQueue中的Message進行處理  
  53.                 //這裡我們再傳回給主線程一個消息  
  54.                 //加入判斷看看是不是該線程自己發的資訊  
  55.                 if(msg.what == 1 && msg.obj.equals("我自己")){  
  56.                     handler = new MyHandler(Looper.getMainLooper());  
  57.                     Message msg2 = handler .obtainMessage(1,1,1,"禀告主線程:我收到了自己發給自己的Message");  
  58.                     handler .sendMessage(msg2);                  
  59.                 }  
  60.             }  
  61.         }  
  62.     }  
  63. }  

附注: 

上面四個例子的布局檔案 是同一個檔案main.xml 

Xml代碼  

Handler,Looper,MessageQueue,Message總結
  1. <?xml version="1.0" encoding="utf-8"?>   
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android rientation="vertical"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"  
  6.     >  
  7. <TextView  android:id="@+id/view_01"  
  8.     android:layout_width="fill_parent"   
  9.     android:layout_height="wrap_content"   
  10.     android:text="@string/hello "  
  11.     />  
  12. <Button android:id="@+id/btn_01"   
  13.     android:layout_width="fill_parent"   
  14.     android:layout_height="wrap_content"   
  15.     android:text="測試消息" />  
  16. </LinearLayout>  

原創部分:

以PowerMangerService裡的handler為例,說明一下handler具體實作過程

總的來說就是handler往MessageQueue裡放消息,Looper.loop()從消息隊列中讀消息,調用handler對象的Handlemessage處理隊列裡的消息。

PowerManagerService.java:

public void init(Context context,LightsService ls,

           ActivityManagerService am, BatteryService bs, IBatteryStats bss,

           IAppOpsService appOps, DisplayManagerService dm) {

     ……

       mHandlerThread = new HandlerThread(TAG);

        mHandlerThread.start(); //大部分都是在這裡做的,請仔細閱讀

        mHandler = newPowerManagerHandler(mHandlerThread.getLooper());

}

HandlerThread.java:

   public HandlerThread(String name) {

        super(name);

       mPriority = Process.THREAD_PRIORITY_DEFAULT;

}

mHandlerThread.start();會調用此run函數

  @Override

    public void run() {

        mTid = Process.myTid();

        Looper.prepare();   \\會new  looper

        synchronized (this) {

            mLooper =Looper.myLooper();  \\擷取上步new的looper

            notifyAll();

        }

        Process.setThreadPriority(mPriority);

        onLooperPrepared();

        Looper.loop(); \\循環監視messageQueue

        mTid = -1;

    }

下面逐個分析run函數裡的這幾個方法:

    public static void prepare() {

        prepare(true);

    }

    private static void prepare(booleanquitAllowed) {

        if (sThreadLocal.get() != null) {

            throw newRuntimeException("Only one Looper may be created per thread");

        }

        sThreadLocal.set(new Looper(quitAllowed)); \\newlooper

    }

   private Looper(boolean quitAllowed) {

//new looper時候new出handler對應的MessageQueue

        mQueue = new MessageQueue(quitAllowed);

        mThread = Thread.currentThread();  //looper跟線程關聯

    }

-----------------------------------------------------

Looper.loop(); 

    public static void loop() {

        final Looper me = myLooper();

        if (me == null) {

            throw new RuntimeException("NoLooper; Looper.prepare() wasn't called on this thread.");

        }

        final MessageQueue queue = me.mQueue;

        // Make sure the identity of thisthread is that of the local process,

        // and keep track of what that identitytoken actually is.

        Binder.clearCallingIdentity();

        final long ident =Binder.clearCallingIdentity();

        for (;;) {

            Message msg = queue.next(); // mightblock//循環檢視消息隊列

            if (msg == null) {

                // No message indicates thatthe message queue is quitting.

                return;

            }

                ………

//messagequeue裡有消息就會調到此方法  target為發送msg時候指派的對應handler

            msg.target.dispatchMessage(msg);     

         if (logging != null) {

               logging.println("<<<<< Finished to " +msg.target + " " + msg.callback);

            }

            // Make sure that during the courseof dispatching the

            // identity of the thread wasn'tcorrupted.

            final long newIdent =Binder.clearCallingIdentity();

            if (ident != newIdent) {

                Log.wtf(TAG, "Threadidentity changed from 0x"

                        +Long.toHexString(ident) + " to 0x"

                        +Long.toHexString(newIdent) + " while dispatching to "

                        +msg.target.getClass().getName() + " "

                        + msg.callback + "what=" + msg.what);

            }

            msg.recycle();  //把這個msg執行個體放回到goable pool

        }

    }

Handler.java

    public void dispatchMessage(Message msg) {

        if (msg.callback != null) {

            handleCallback(msg);

        } else {

            if (mCallback != null) {

                if (mCallback.handleMessage(msg)){

                    return;

                }

            }

            handleMessage(msg);  \\這就是newhandler時候@override的handlemessage(msg)

        }

    }

    public void recycle() {

        clearForRecycle();  //msg裡資訊清楚

        synchronized (sPoolSync) {

            if (sPoolSize < MAX_POOL_SIZE) {

                next = sPool;

                sPool = this;  添加到sPool裡 message msg =  handler.obtain()就是從sPool裡配置設定一個message對象

                sPoolSize++;

            }

        }

    }

建立和接收到此為止,下面說下handler怎麼把msg發送到到MessageQueue裡的

  Handler.sendEmptyMessageAtTime(int what, longuptimeMillis)為例:

 public final booleansendEmptyMessageAtTime(int what, long uptimeMillis) {

        Message msg = Message.obtain();

        msg.what = what;

        returnsendMessageAtTime(msg, uptimeMillis);

    }

    public boolean sendMessageAtTime(Messagemsg, long uptimeMillis) {

        //把handler對象的MessageQueue賦給queue

        MessageQueuequeue = mQueue;  

        if (queue == null) {

            RuntimeException e = newRuntimeException(

                    this + "sendMessageAtTime() called with no mQueue");

            Log.w("Looper",e.getMessage(), e);

            return false;

        }

        return enqueueMessage(queue, msg,uptimeMillis);

    }

    private boolean enqueueMessage(MessageQueuequeue, Message msg, long uptimeMillis) {

        msg.target =this;  //上面再loop裡用到的target指派 this為目前handler對象

        if (mAsynchronous) {

            msg.setAsynchronous(true);

        }

        return queue.enqueueMessage(msg,uptimeMillis);  //MessageQueue.java裡

    }

MessageQueue.java:

booleanenqueueMessage(Message msg, long when) {

        if (msg.isInUse()) {

            throw newAndroidRuntimeException(msg + " This message is already in use.");

        }

        if (msg.target== null) {  //判斷設定的target是否為NULL

            throw newAndroidRuntimeException("Message must have a target.");

        }

        synchronized (this) {

            if (mQuitting) {

                RuntimeException e = newRuntimeException(

                        msg.target + " sending message toa Handler on a dead thread");

                Log.w("MessageQueue",e.getMessage(), e);

                return false;

            }

            msg.when = when;

            Message p = mMessages; //mMessages為隊列裡最新的一個Message

            boolean needWake;

            if (p == null || when == 0 || when< p.when) {

                // New head, wake up the eventqueue if blocked.

                msg.next = p;

                mMessages = msg;

                needWake = mBlocked;

            } else {

                // Inserted within the middleof the queue.  Usually we don't have towake

                // up the event queue unlessthere is a barrier at the head of the queue

                // and the message is theearliest asynchronous message in the queue.

                needWake = mBlocked &&p.target == null && msg.isAsynchronous();

                Message prev;

//把msg加到MessageQueue裡此函數執行完後再loop循環裡就可以讀取到此消息

                for (;;) {

                   prev = p;

                    p = p.next;

                    if(p == null || when < p.when) {

                       break;

                    }

                    if(needWake && p.isAsynchronous()) {

                       needWake = false;

                    }

                }

               msg.next = p; // invariant: p == prev.next

               prev.next = msg;

            }

            // We can assume mPtr != 0 becausemQuitting is false.

            if (needWake) {

                nativeWake(mPtr);

            }

        }

        return true;

    }

一個handler 隻能對應一個Looper 一個MessageQueue

一個Thread  隻能有一個Looper

New Handler()時候如果沒有傳入Looper預設用主線程的Looper作為此handler的Looper

有任何問題請留言,謝謝!