轉載部分來自: 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代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1cldWYtl2Lc12bj5SZ5VGdp5CMwEzdtVHZuV3Zvw1LcpDc0RHaiojIsJye.png)
- package test.message;
- import android .app .Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.view.View ;
- import android.widget.Button;
- import android.widget.TextView ;
- public class MainActivity extends Activity {
- private Button btnTest;
- private TextView textView;
- private Handler handler ;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnTest = (Button)this.findViewById(R.id.btn_01);
- textView = (TextView)this.findViewById(R.id.view_01);
- btnTest.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View arg0) {
- Looper looper = Looper.getMainLooper(); //主線程的Looper對象
- //這裡以主線程的Looper對象建立了handler ,
- //是以,這個handler 發送的Message會被傳遞給主線程的MessageQueue。
- handler = new MyHandler(looper);
- handler .removeMessages(0);
- //建構Message對象
- //第一個參數:是自己指定的message代号,友善在handler 選擇性地接收
- //第二三個參數沒有什麼意義
- //第四個參數需要封裝的對象
- Message msg = handler .obtainMessage(1,1,1,"主線程發消息了");
- handler .sendMessage(msg); //發送消息
- }
- });
- }
- class MyHandler extends Handler{
- public MyHandler(Looper looper){
- super(looper);
- }
- public void handleMessage(Message msg){
- super.handleMessage(msg);
- textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);
- }
- }
- }
2、其他線程給主線程發送Message
Java代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1cldWYtl2Lc12bj5SZ5VGdp5CMwEzdtVHZuV3Zvw1LcpDc0RHaiojIsJye.png)
- package test.message;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- public class MainActivity extends Activity {
- private Button btnTest;
- private TextView textView;
- private Handler handler ;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnTest = (Button)this.findViewById(R.id.btn_01);
- textView = (TextView)this.findViewById(R.id.view_01);
- btnTest.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View arg0) {
- //可以看出這裡啟動了一個線程來操作消息的封裝和發送的工作
- //這樣原來主線程的發送就變成了其他線程的發送,簡單吧?呵呵
- new MyThread().start();
- }
- });
- }
- class MyHandler extends Handler{
- public MyHandler(Looper looper){
- super(looper);
- }
- public void handleMessage(Message msg){
- super.handleMessage(msg);
- textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);
- }
- }
- //加了一個線程類
- class MyThread extends Thread{
- public void run(){
- Looper looper = Looper.getMainLooper(); //主線程的Looper對象
- //這裡以主線程的Looper對象建立了handler ,
- //是以,這個handler 發送的Message會被傳遞給主線程的MessageQueue。
- handler = new MyHandler(looper);
- //建構Message對象
- //第一個參數:是自己指定的message代号,友善在handler 選擇性地接收
- //第二三個參數沒有什麼意義
- //第四個參數需要封裝的對象
- Message msg = handler .obtainMessage(1,1,1,"其他線程發消息了");
- handler .sendMessage(msg); //發送消息
- }
- }
- }
3、主線程給其他線程發送Message
Java代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1cldWYtl2Lc12bj5SZ5VGdp5CMwEzdtVHZuV3Zvw1LcpDc0RHaiojIsJye.png)
- package test.message;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- public class MainActivity extends Activity {
- private Button btnTest;
- private TextView textView;
- private Handler handler ;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnTest = (Button)this.findViewById(R.id.btn_01);
- textView = (TextView)this.findViewById(R.id.view_01);
- //啟動線程
- new MyThread().start();
- btnTest.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View arg0) {
- //這裡handler 的執行個體化線上程中
- //線程啟動的時候就已經執行個體化了
- Message msg = handler .obtainMessage(1,1,1,"主線程發送的消息");
- handler .sendMessage(msg);
- }
- });
- }
- class MyHandler extends Handler{
- public MyHandler(Looper looper){
- super(looper);
- }
- public void handleMessage(Message msg){
- super.handleMessage(msg);
- textView.setText("我是主線程的Handler,收到了消息:"+(String)msg.obj);
- }
- }
- class MyThread extends Thread{
- public void run(){
- Looper.prepare(); //建立該線程的Looper對象,用于接收消息
- //注意了:這裡的handler 是定義在主線程中的哦,呵呵,
- //前面看到直接使用了handler 對象,是不是在找,在什麼地方執行個體化的呢?
- //現在看到了吧???呵呵,開始的時候執行個體化不了,因為該線程的Looper對象
- //還不存在呢。現在可以執行個體化了
- //這裡Looper.myLooper()獲得的就是該線程的Looper對象了
- handler = new ThreadHandler(Looper.myLooper());
- //這個方法,有疑惑嗎?
- //其實就是一個循環,循環從MessageQueue中取消息。
- //不經常去看看,你怎麼知道你有新消息呢???
- Looper.loop();
- }
- //定義線程類中的消息處理類
- class ThreadHandler extends Handler{
- public ThreadHandler(Looper looper){
- super(looper);
- }
- public void handleMessage(Message msg){
- //這裡對該線程中的MessageQueue中的Message進行處理
- //這裡我們再傳回給主線程一個消息
- handler = new MyHandler(Looper.getMainLooper());
- Message msg2 = handler .obtainMessage(1,1,1,"子線程收到:"+(String)msg.obj);
- handler .sendMessage(msg2);
- }
- }
- }
- }
4、其他線程給自己發送Message
Java代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1cldWYtl2Lc12bj5SZ5VGdp5CMwEzdtVHZuV3Zvw1LcpDc0RHaiojIsJye.png)
- package test.message;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- public class MainActivity extends Activity {
- private Button btnTest;
- private TextView textView;
- private Handler handler ;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnTest = (Button)this.findViewById(R.id.btn_01);
- textView = (TextView)this.findViewById(R.id.view_01);
- btnTest.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View arg0) {
- //啟動線程
- new MyThread().start();
- }
- });
- }
- class MyHandler extends Handler{
- public MyHandler(Looper looper){
- super(looper);
- }
- public void handleMessage(Message msg){
- super.handleMessage(msg);
- textView.setText((String)msg.obj);
- }
- }
- class MyThread extends Thread{
- public void run(){
- Looper.prepare(); //建立該線程的Looper對象
- //這裡Looper.myLooper()獲得的就是該線程的Looper對象了
- handler = new ThreadHandler(Looper.myLooper());
- Message msg = handler .obtainMessage(1,1,1,"我自己");
- handler .sendMessage(msg);
- Looper.loop();
- }
- //定義線程類中的消息處理類
- class ThreadHandler extends Handler{
- public ThreadHandler(Looper looper){
- super(looper);
- }
- public void handleMessage(Message msg){
- //這裡對該線程中的MessageQueue中的Message進行處理
- //這裡我們再傳回給主線程一個消息
- //加入判斷看看是不是該線程自己發的資訊
- if(msg.what == 1 && msg.obj.equals("我自己")){
- handler = new MyHandler(Looper.getMainLooper());
- Message msg2 = handler .obtainMessage(1,1,1,"禀告主線程:我收到了自己發給自己的Message");
- handler .sendMessage(msg2);
- }
- }
- }
- }
- }
附注:
上面四個例子的布局檔案 是同一個檔案main.xml
Xml代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1cldWYtl2Lc12bj5SZ5VGdp5CMwEzdtVHZuV3Zvw1LcpDc0RHaiojIsJye.png)
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android rientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView android:id="@+id/view_01"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/hello "
- />
- <Button android:id="@+id/btn_01"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="測試消息" />
- </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
有任何問題請留言,謝謝!