Android中的消息機制主要就是指Handler的消息機制,Handler相信大家已經非常熟悉了,它可以將一個任務切換到Handler所在的線程中去執行,開發中,當我們在子線程做了一些操作后需要更新UI,由于Android不允許在子線程中訪問UI控件,所以我們一般都會使用handler來實現。
Handler的機制需要MessageQueue、Looper和Message的支持。他們在消息機制中各扮演了不同的角色
Handler:負責消息的發送和接收處理
MessageQueue:消息隊列,一個消息存儲單位,經常需要進行增減,內部使用的是單鏈表的結構
Looper:消息循環。會不停地從MessageQueue中取消息,如果有新消息就會立刻處理,否則就一直阻塞在那里
Message:消息載體
下面通過一段簡單的代碼來分析整個執行過程。
private TextView textView;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
textView.setText("消息處理.....");
}
};
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.mytv);
new Thread(new Runnable() {
@Override
public void run() {
//模擬耗時操作
SystemClock.sleep(3000);
handler.sendMessage(new Message());
}
}).start();
}
就是在子線程中做了一些耗時操作后,通過Handler發送消息去更新UI
Hanlder是怎么接受到消息的呢?
Looper
Looper幾個主要的方法
- Looper.prepare():為當前線程創建一個Looper
- Looper.loop():開啟消息循環
- Looper.getMainLoop():可以在任何地方獲取到主線程的
- Looper.quit():直接退出Looper
- quitSafely():設置一個標記,把消息隊列的所有消息處理完后才會退出
//創建一個新的Looper并放到當前線程的ThreadLocal中去
private static void prepare(boolean quitAllowed){
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
再看看Looper的構造方法,發現,Looper中保存有一個MessageQueue
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
loop()該方法是一個死循環,會不斷從MessageQueue中去取消息,當獲取到消息后,將交由Handler去處理
public static void loop() {
//myLooper方法會從ThreadLocal中獲取到當前線程的Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
//不斷的去MessageQueue中取消息
Message msg = queue.next();
if (msg == null) {
return;
}
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); }
//調用發送該消息的Handler的dispatchMessage方法處理該消息
//這里的msg.target == Handler,是在Handler發送消息的時候進行賦值的
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); }
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
Looper大概就是這么一回事,每條線程綁定一個Looper(子線程需要自己調用Loop.prepare()),保證每條線程都只有一個Looper實例
隨后調用Looper.loop開啟消息循環,進入堵塞狀態,等待消息的到來
MessageQueue
相對來說就很簡單來,就兩個操作,插入和讀取。可以看成一個消息容器
Handler
先來看看他的構造方法
```java
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); }
}
//獲取當前線程中的Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
//如果當前線程沒有Looper就會拋出異常。
throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");
}
//獲取Looper中的MessageQueue,可以看出,Looper中為每個線程維護了一個Message
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
接來下看看Handler發送消息的方法,追蹤senndmessage到最底層的方法就是enqueueMessage。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
主要做了兩個操作
msg.target = this;將發送的Message的target指向當前Handler。
ueue.enqueueMessage(msg, uptimeMillis);往當前線程的MessageQueue插入一條消息
前面在Looper.looper()方法中我們看到msg.target.dispatchMessage(msg); 獲取到消息后,調用Handler的dispatchMessage方法進行消息處理。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);//這里是Message的Callback,也就是開啟我們在postDelayed傳入的Runnable
} else {
//mCallback:構造器傳入的實現
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//handler自己的handler,一般由派生之類來實現
handleMessage(msg);
}
}
可以看到Handler最終將調用handlerMessage處理消息,當然這里的handlerMessage處理是有優先級的
下面我們總結下流程
流程總結:
1,首先調用Looper.prepare()方法,會創建一個Looper實例,該實例包含一個MessageQueue,并將該實例保存在當前線程中Threadlocal
2,調用Looper.loop()開始消息循環,不斷地向MessageQueue中讀取消息,并調用msg.target.dispatchMessage(msg);來處理消息
3,構建Handler的時候,會先獲取到當前Handler所在線程的Looper并得到其中的 MessageQueue
4,使用Handler發送消息的時候,會將一個Message到保存當前線程Looper中的MessageQueue
5,當Looper.loop()獲取到消息的時候,調用msg.target.dispatchMessage(msg)來處理消息,其實Message.target = handler。也就是調用Handler的dispatchMessage來處理
6,Handler的dispatchMessage最終回去調用handlerMessage方法。到這里就知道,其實Handler的handler在哪條線程執行,取決于構建Handler時所使用的是哪條線程保存的Looper,因為handlerMessage其實是Looper去調用的。
下面通過一張圖來表述下具體流程
前面說到,Handler必須有Looper才能執行,或者會就拋出異常,當前我們在日常使用中,直接在Activity中定義Handler就可以用啦,并沒有說調用Looper.prepare來進行初始化操作。
其實UI線程默認已經做了這些操作了。對于我們來說是隱形的
大家都知道Android的程序入口是ActivityThread類,他有個main方法,我們看看他做了什么
public static void main(String[] args) {
//省略。。。。
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看到main方法主要就是消息循環,當main方法結束了,你的程序也就退出了
可能有人會問?UI線程已經做了Looper.loop()了?loop不是一個死循環堵塞狀態嗎?為什么我們程序還能跑起來。
既然main方法只是做了消息循環,那么我們Activity的生命周期的方法是怎么執行的呢?
在ActivityThread中有個Handler,Activity的生命周期方法在里面均有case,也就說是我們的代碼其實就是在這個循環里面去執行的,自然不會阻塞了
當前我還有個疑惑。程序是在哪給ActivityThread的Handler發消息的呢?這個我暫時還不清楚。。還得繼續學習啊。
UI線程已經幫我們做了這些工作了,但是如果我們自己new Thread的話,需要在子線程中使用Handler的話,還是要自己來實現的。
對此,Android也為我們提供了一個HandlerThread類,方便我們快速的實現需求。
HandlerThread繼承了Thread
public class HandlerThread extends Thread
代碼相當簡單,
看看run方法
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
如果對前面的Handler機制理解了話,這里是不是一目了然了呢?