Android處理程序:Handler Looper Message源碼研究
線程Thread的線程變量ThreadLocal中,存放著這個線程的Looper;Looper在初始化時,會新建一個消息隊列MessageQueue,之后Looper進(jìn)入一個死循環(huán),等待從消息隊列MessageQueue取得消息Message(Looper是消費者),沒有消息時會阻塞;
我們程序中的Handler,會通過sendMessage或post方法,往MessageQueue中添加消息時,添加的這個Message,會記錄他是屬于哪個Handler發(fā)出的,同時根據(jù)message.when,決定新添加的這個Message在Queue中的位置,MessageQueue中只有一個當(dāng)前的Message,隊列關(guān)系是通過Message中的prev,next維護(hù)的,Message是一個鏈表的節(jié)點;
添加消息后,消費者Looper取得Message,并調(diào)用建立Message的Hander的dispatchMessage方法。
咋一看好像Handler即sendMessage,又handlerMessage,事情還是只有一個線程在做事情。
但是后來想想,明白了這樣設(shè)計的必要性。
因為這個***的線程一般而言,都是mainUI線程,如果你有個可以分成多個小任務(wù)的任務(wù)要處理,你沒有使用Handler,直接執(zhí)行,也許系統(tǒng)忙于處理你這個任務(wù),而無法及時響應(yīng)用戶事件,從而導(dǎo)致ANR的拋出。
如果你把你的任務(wù)拆成幾個小任務(wù),用Handler來實現(xiàn),那么系統(tǒng)就可以把你的小任務(wù)推到后面來處理,抽出時間來響應(yīng)用戶操作。
如果真的有大任務(wù),一般式需要另外線程去處理,或者開啟Service。
一個在新線程中使用handler例子,我們來分析下源碼
Java代碼
- new Thread(new Runnable() {
- @Override public void run() {
- Handler handler;
- //1、初始化Looper
- Looper.prepare();
- //2、綁定handler到CustomThread實例的Looper對象、定義處理消息的方法
- handler= new Handler() {
- @Override public void handleMessage(Message msg) {
- }
- };
- // 3、發(fā)送消息
- handler.sendMessage(new Message());
- handler.post(new Runnable())
- handler.obtainMessage(1, "hello").sendToTarget();
- //4、啟動消息循環(huán)
- Looper.loop();
- }
- }).start();
1 Java代碼
- public static final void prepare() {
- if (sThreadLocal.get() != null) { // 每個線程,只能有一個Looper對象
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- // 如果當(dāng)前線程沒有Looper,新建一個,構(gòu)造函數(shù)是private的
- sThreadLocal.set(new Looper());
- }
- private Looper() {
- mQueue = new MessageQueue(); // 建立消息隊列
- mRun = true;
- mThread = Thread.currentThread();
- }
2 Java代碼
- public Handler(){
- mLooper = Looper.myLooper(); // 取得當(dāng)前線程的Looper,如果拋異常
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()");
- }
- mQueue = mLooper.mQueue; // 取得消息隊列
- mCallback = null;
- }
3 Java代碼
- //不管調(diào)用哪個方法,最終執(zhí)行的是
- public boolean sendMessageAtTime(Message msg, long uptimeMillis){
- boolean sent = false;
- // 取得消息隊列
- MessageQueue queue = mQueue;
- if (queue != null) {
- msg.target = this; // 消息發(fā)出著是自己
- sent = queue.enqueueMessage(msg, uptimeMillis); // 添加到消息隊列中
- }
- else {
- RuntimeException e = new RuntimeException(
- this + " sendMessageAtTime() called with no mQueue");
- Log.w("Looper", e.getMessage(), e);
- }
- return sent;
- }
- final boolean enqueueMessage(Message msg, long when) {
- if (msg.when != 0) {
- throw new AndroidRuntimeException(msg
- + " This message is already in use.");
- }
- if (msg.target == null && !mQuitAllowed) {
- throw new RuntimeException("Main thread not allowed to quit");
- }
- synchronized (this) {
- if (mQuiting) {
- RuntimeException e = new RuntimeException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w("MessageQueue", e.getMessage(), e);
- return false;
- } else if (msg.target == null) {
- mQuiting = true;
- }
- msg.when = when;
- Message p = mMessages;
- // 之前沒有其他消息了,MessageQueue中當(dāng)前消息mMessages 就是傳遞進(jìn)來的msg
- if (p == null || when == 0 || when < p.when) {
- msg.next = p;
- mMessages = msg;
- this.notify(); // 喚醒
- } else {
- // 之前有其他消息了,將傳遞的msg放到適合的位置,根據(jù)when
- Message prev = null;
- while (p != null && p.when <= when) {
- prev = p;
- p = p.next;
- }
- msg.next = prev.next;
- prev.next = msg;
- this.notify(); // 喚醒
- }
- }
- return true;
- }
4 Java代碼
- public static final void loop() {
- Looper me = myLooper();
- MessageQueue queue = me.mQueue;
- while (true) { // 死循環(huán)
- Message msg = queue.next(); // 當(dāng)隊列中沒有消息時會阻塞
- if (msg != null) {
- if (msg.target == null) { // 消息沒有發(fā)送者時,退出消息循環(huán)
- // No target is a magic identifier for the quit message.
- return;
- }
- if (me.mLogging!= null) me.mLogging.println(
- ">>>>> Dispatching to " + msg.target + " "
- + msg.callback + ": " + msg.what
- );
- // 調(diào)用消息發(fā)出者的dispatchMessage,這里msg.target是我們sendMessage的handler
- msg.target.dispatchMessage(msg);
- if (me.mLogging!= null) me.mLogging.println(
- "<<<<< Finished to " + msg.target + " "
- + msg.callback);
- msg.recycle();
- }
- }
- }
- final Message next() {
- boolean tryIdle = true;
- while (true) {
- synchronized (this) {
- // 沒有消息的或,會阻塞
- try {
- if (mMessages != null) {
- if (mMessages.when-now > 0) {
- Binder.flushPendingCommands();
- this.wait(mMessages.when-now);
- }
- } else {
- Binder.flushPendingCommands();
- this.wait();
- }
- }
- catch (InterruptedException e) {
- }
- }
- }
- }
總結(jié)
Handler作用:
1. 執(zhí)行計劃任務(wù)
2. 線程間通信
一個handler,只能接收到自己發(fā)出的message。handler實例與消息Message處理是關(guān)聯(lián)的,發(fā)送和接受要匹配
Handler操作隊列,主要是在子線程操作主線程的消息隊列
Handler是實現(xiàn)異步的一種方式,用法是在主線程中建立Handler,(主線程中的Handler不用掉Looper.prepare);
在子線程(耗時操作)任務(wù)完成后sendMessage,這個Message會發(fā)送到主線程的消息隊列中,主線程Handler的重寫dispatchMessage方法,做新線程任務(wù)完成后的事情,大部分是更新UI。