1. 程式人生 > >Handler用法及解析

Handler用法及解析

 

 

目錄

1.handler作用: 

1)傳遞訊息Message

2)子執行緒通知主執行緒更新ui

2.常用api

3.handler使用避免記憶體洩露

 1)handler怎麼使用會產生記憶體洩露?

 2)如何避免handler的記憶體洩露?

 3)  雷區

4.handlerThread

1)  handlerThread是什麼?

2)HandlerThread使用及銷燬

5.原始碼解析

1)Message訊息

2)Looper

3)  MessageQueue訊息佇列

4)Handler

6.總結


1.handler作用: 

1)傳遞訊息Message

//2種建立訊息方法
//1.通過handler例項獲取
Handler handler = new Handler();
Message message=handler.obtainMessage();

//2.通過Message獲取
Message message=Message.obtain();


//原始碼中第一種獲取方式其實也是內部呼叫了第二種:
public final Message obtainMessage(){
    return Message.obtain(this);
}

不建議直接new Message,Message內部儲存了一個快取的訊息池,我們可以用obtain從快取池獲得一個訊息,Message使用完後系統會呼叫recycle回收,如果自己new很多Message,每次使用完後系統放入快取池,會佔用很多記憶體的。 

//傳遞的資料
Bundle bundle = new Bundle();
bundle.putString("msg", "傳遞我這個訊息");
//傳送資料
Message message = Message.obtain();
message.setData(bundle);   //message.obj=bundle  傳值也行
message.what = 0x11;
handler.sendMessage(message);



//資料的接收
final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 0x11) {
                Bundle bundle = msg.getData();
                String date = bundle.getString("msg");
            }
        }
};

2)子執行緒通知主執行緒更新ui

        //建立handler
        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == 0x11) {
                    //更新ui
                          ......
                }
            }
        };

        new Thread(new Runnable() {
            @Override
            public void run() {
                //FIXME 這裡直接更新ui是不行的
                //還有其他更新ui方式,runOnUiThread()等          
                message.what = 0x11;     
                handler.sendMessage(message);  
            }
        }).start();

2.常用api

    //訊息
    Message message = Message.obtain();
    //傳送訊息
        new Handler().sendMessage(message);
    //延時1s傳送訊息
        new Handler().sendMessageDelayed(message, 1000);
    //傳送帶標記的訊息(內部建立了message,並設定msg.what = 0x1)
        new Handler().sendEmptyMessage(0x1);
    //延時1s傳送帶標記的訊息
        new Handler().sendEmptyMessageDelayed(0x1, 1000);
    //延時1秒傳送訊息(第二個引數為:相對系統開機時間的絕對時間,而SystemClock.uptimeMillis()是當前開機時間)
        new Handler().sendMessageAtTime(message, SystemClock.uptimeMillis() + 1000);

    //避免記憶體洩露的方法:
    //移除標記為0x1的訊息
        new Handler().removeMessages(0x1);
    //移除回撥的訊息
        new Handler().removeCallbacks(Runnable);
    //移除回撥和所有message
        new Handler().removeCallbacksAndMessages(null);

3.handler使用避免記憶體洩露

 1)handler怎麼使用會產生記憶體洩露?

public class MainActivity extends AppCompatActivity {

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
                ......
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //activity被執行時,被延遲的這個訊息存於主執行緒訊息佇列中1分鐘,
        //此訊息包含handler引用,而handler由匿名內部類建立,持有activity引用,
        //activity便不能正常銷燬,從而洩露
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                ......
            }
        }, 1000 * 60);
    }
}

 2)如何避免handler的記憶體洩露?

public class MainActivity extends AppCompatActivity {

    //建立靜態內部類
    private static class MyHandler extends Handler{
        //持有弱引用MainActivity,GC回收時會被回收掉.
        private final WeakReference<MainActivity> mAct;
        public MyHandler(MainActivity mainActivity){
            mAct =new WeakReference<MainActivity>(mainActivity);
        }
        @Override
        public void handleMessage(Message msg) {
            MainActivity mainAct=mAct.get();
            super.handleMessage(msg);
            if(mainAct!=null){
                //執行業務邏輯
            }
        }
    }
    private static final Runnable myRunnable = new Runnable() {
        @Override
        public void run() {
            //執行我們的業務邏輯
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyHandler myHandler=new MyHandler(this);
        //延遲5分鐘後傳送
        myHandler.postDelayed(myRunnable, 1000 * 60 * 5);
    }
}

 3)  雷區

a)Handler.post(Runnable)其實就是生成一個what為0的Message,呼叫

myHandler.removeMessages(0);

會使runnable任務從訊息佇列中清除。

詳細解釋:https://www.cnblogs.com/coding-way/p/5110125.html(轉)

b) 子執行緒直接建立Handler,拋異常Can't create handler inside thread that has not called Looper.prepare()

原因是非主執行緒沒有loop物件,所以要呼叫Looper.prepare()方法,而且如果主執行緒給子執行緒傳送訊息,還要呼叫一個Looper.loop()的方法(此方法保證訊息佇列中的訊息被不停的拿出,並被處理)

class MyThread extends Thread{
        @Override
        public void run() {
            super.run();
            Looper.prepare();
            Handler handler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    //處理訊息
                }
            };
            Looper.loop();
        }
}

c)activity如被finish,但是handler剛好還在處理訊息,如果需要用的資源已被釋放,則會出現空指標異常。

所以在ondestory中去remove掉我們要處理的事件,還是有必要的。不想處理就直接try catch或者判空。

d)有時候你會發現removeCallbacks會失效,不能從訊息佇列中移除。

出現這情況是activity切入後臺,再回到前臺,此時的runnable由於被重定義,就會和原先的runnable並非同一個物件。所以這麼做,加上static即可

static Handler handler = new Handler();
static Runnable myRunnable = new Runnable() {
        @Override
        public void run() {
            //執行我們的業務邏輯
        }
    };

這樣,因為靜態變數在記憶體中只有一個拷貝,保證runnable始終是同一個物件。

4.handlerThread

1)  handlerThread是什麼?

(題外話:非同步存在形式有thread,handlerThead,asyncTask,執行緒池,intentService)

handlerThread繼承thread,不過內部比普通執行緒多了一個Looper

//內部Looper.prepare()
@Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
}

2)HandlerThread使用及銷燬

public class MainActivity extends AppCompatActivity {

    private HandlerThread thread;
    static Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //建立一個HandlerThread並啟動它
        thread = new HandlerThread("MyHandlerThread");
        thread.start();

        //使用HandlerThread的looper物件建立Handler
        mHandler = new Handler(thread.getLooper(), new Handler.Callback() {
            @Override
            public boolean handleMessage(Message msg) {
                //這個方法是執行在 handler-thread 執行緒中的,可以執行耗時操作,因此不能更新ui,要注意
                if (msg.what == 0x1) {
                    try {
                        Thread.sleep(3000);
                        Log.e("測試: ", "執行了3s的耗時操作");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //這個方法是執行在 handler-thread 執行緒中的,可以執行耗時操作,因此不能更新ui,要注意
//                    ((Button) MainActivity.this.findViewById(R.id.button)).setText("hello");
                }
                return false;
            }
        });

        //停止handlerthread接收事件
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                thread.quit();
            }
        });

        //執行
        mHandler.sendEmptyMessage(0x1);
    }

}

上面demo中,只要呼叫了

mHandler.sendEmptyMessage(0x1);

就會開始執行任務

幾個地方要注意:

a.handleMessage()可以做耗時操作,但是不能更新ui

b.如果不手動的呼叫HandlerThread.quit()或者HandlerThread..quitSafely()方法,HandlerThread會將持續的接收新的任務事件。

c.只有handleMessage()方法執行完,這輪的任務才算完成,HandlerThread才會去執行下一個任務。而且在此次執行時,即使手動的去呼叫quit()方法,HandlerThread的此次任務也不會停止。但是,會停止下輪任務的接收。

舉例:

//耗時任務換成這個,點選按鈕執行quit()方法,發現此次任務依舊執行
for (int i = 0; i < 99999999; i++) {
    Log.e("測試: ", "輸出" +i);
}

d.HandlerThread的2種停止接收事件的方法。

第一個就是quit(),實際上執行了MessageQueue中的removeAllMessagesLocked方法,該方法的作用是把MessageQueue訊息池中所有的訊息全部清空,無論是延遲訊息(帶Delayed的)還是非延遲訊息。

第二個就是quitSafely(),執行了MessageQueue中的removeAllFutureMessagesLocked方法,該方法只會清空MessageQueue訊息池中所有的延遲訊息,並將訊息池中所有的非延遲訊息派發出去讓Handler去處理,quitSafely相比於quit方法安全之處在於清空訊息之前會派發所有的非延遲訊息

MessageQueue中原始碼:

void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }
        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }
            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
}
舉例:

//quit方法後,即使傳送新事件,也不會被接收
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
              thread.quit();
              //傳送新事件
              mHandler.sendEmptyMessage(0x1);
        }
);

e.即使多次執行mHandler.sendEmptyMessage(0x1),任務佇列中的任務依然只能一個一個的被處理。上一任務結束,開始執行下一個。

日誌顯示:輸出0-99的任務結束,才執行下個輸出0-99的任務
08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出95
08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出96
08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出97
08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出98
08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出99
08-09 20:17:05.718 12618-12762/com.bihucj.mcandroid E/測試:: 輸出0
08-09 20:17:05.718 12618-12762/com.bihucj.mcandroid E/測試:: 輸出1
08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/測試:: 輸出2
08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/測試:: 輸出3
08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/測試:: 輸出4
08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/測試:: 輸出5

 

5.原始碼解析

說到原始碼,主要還是幾個關鍵詞。分別為Message,Looper,MessageQueue,Handler。還有Thread

先說Looper,MessageQueue,Handler3者關聯的思路:

主執行緒-->prepareMainLooper()(內部呼叫prepare() ,去例項化Looper,Looper例項化同時建立了messagequeue,11對應關係)-->主執行緒中的handler獲取當前執行緒的Looper-->3者關聯

插播主執行緒ActivityThread:

public static void main(String[] args) {
        ......
        Looper.prepareMainLooper();

        ......
        //區別:子執行緒是建立handler;
        //主執行緒是通過getHandler()獲取內部類例項
        if(sMainThreadHandler==null){
        sMainThreadHandler=thread.getHandler();
        }
        ......
}


private class H extends Handler{
   ......
}

子執行緒-->直接通過Looper.prepare()去例項化Looper,Looper例項化同時建立了messagequeue(11對應關係) -->例項化Handler同時獲取當前子執行緒的Looper-->3者關聯

1)Message訊息

public final class Message implements Parcelable {

//使用者定義的訊息程式碼,以便接收者能夠識別
public int what;

//arg1和arg2是使用成本較低的替代品-也可以用來儲存int值
public int arg1;
public int arg2;

//存放任意型別的物件
public Object obj;

//訊息觸發時間
long when;

//訊息攜帶內容
Bundle data;

//訊息響應方
Handler target;

//訊息管理器,會關聯到一個handler
public Messanger replyTo;

//回撥方法
Runnable callback;

//訊息儲存的連結串列。這樣sPool就成為了一個Messages的快取連結串列。
Message next;

//訊息池
private static Message sPool;

//訊息池的預設大小
private static final int MAX_POOL_SIZE = 50;


//從訊息池中獲取訊息
public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool; //從sPool的表頭拿出Message
            sPool = m.next;  //將訊息池的表頭指向下一個Message
            m.next = null; //將取出訊息的連結串列斷開
            m.flags = 0; // 清除flag----flag標記判斷此訊息是否正被使用(下方isInUse方法)
            sPoolSize--; //訊息池可用大小進行減1
            return m;
        }
    }
    return new Message(); //訊息池為空-直接建立Message
}

//通過標記判斷訊息是否正被使用
boolean isInUse() {
   return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
}

//5.0後為true,之前為false.
private static boolean gCheckRecycle = true;


public void recycle() {
  if (isInUse()) { 
     if (gCheckRecycle) { 
            throw new IllegalStateException("This message cannot be recycled because it is still in use.");
        }
        return;
    }
  recycleUnchecked();  //訊息沒在使用,回收
}


//對於不再使用的訊息,加入到訊息池
void recycleUnchecked() {
    //將訊息標示位置為IN_USE,並清空訊息所有的引數。
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;
    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;  
            sPool = this; //當訊息池沒有滿時,將Message加入訊息池
            sPoolSize++; //訊息池可用大小加1
        }
    }
}

2)Looper

 https://blog.csdn.net/woshiluoye9/article/details/72544764 (轉)

插播ThreadLocal:

ThreadLocal是執行緒的區域性變數, 是每一個執行緒所單獨持有的,其他執行緒不能對其進行訪問。

主執行緒和子執行緒中的Looper的初始化

public final class Looper {

//內部訊息佇列MessageQueue
final MessageQueue mQueue;

//Looper所在的執行緒
final Thread mThread;

//Looper的變數儲存
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

//主looper
private static Looper sMainLooper;


//私有構造方法,不能通過New例項化。
private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);//建立與其繫結的訊息佇列MessageQueue
        mThread = Thread.currentThread(); //綁定當前執行緒
}


//子執行緒的呼叫----->最終通過prepare(boolean)例項化Looper
public static void prepare() {
      prepare(true);
}


//主執行緒的呼叫----->最終通過prepare(boolean)例項化Looper
public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
      if (sMainLooper != null) {
         throw new IllegalStateException("The main Looper has already been prepared.");
           }
            sMainLooper = myLooper();//儲存區中looper作為主looper
        }
}

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
}


//quitAllowed代表是否允許退出,主執行緒呼叫為不允許退出,子執行緒為可退出
private static void prepare(boolean quitAllowed) {
   if (sThreadLocal.get() != null) {
       //看出一個執行緒只能存在一個Looper-->則呼叫二次Looper.prepare丟擲異常
       throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));//Looper的變數儲存+例項化Looper
}

Loop()方法,迴圈取出messagequeue訊息佇列中的訊息,並分發出去。再把分發後的Message回收到訊息池,以便重複利用。

public static void loop() {
    final Looper me = myLooper(); //從儲存區拿出looper
    if (me == null) {
       throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;  //獲取Looper物件中的訊息佇列
    ......
    //進入loop的主迴圈方法
    for (;;) { 
        Message msg = queue.next(); //可能會阻塞 
        if (msg == null) { //沒有訊息,則退出迴圈
            return;
        }
        ......
        //target是handler,此處用於分發Message 
        msg.target.dispatchMessage(msg); 
        ......
        msg.recycleUnchecked();  //將Message放入訊息池
    }
}

Looper中的quit方法-->呼叫的還是messageQueue中的quit()

 public void quit() {
        mQueue.quit(false);
}

3)  MessageQueue訊息佇列

a)主要引數和構造方法

public final class MessageQueue {

//供native程式碼使用
@SuppressWarnings("unused")
private long mPtr;

//交給native層來處理的核心方法
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native void nativePollOnce(long ptr, int timeoutMillis); //阻塞操作
private native static void nativeWake(long ptr);
private native static boolean nativeIsPolling(long ptr);
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);

Message mMessages;

//訊息佇列是否可以退出
private final boolean mQuitAllowed;


//構造方法
MessageQueue(boolean quitAllowed) {
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();  //通過native方法初始化訊息佇列,其中mPtr是供native程式碼使用
}

b)核心的next()方法

//不停提取下一條message
Message next() {
    final long ptr = mPtr;
    //判斷是否退出訊息迴圈
    if (ptr == 0) {
        return null;
    }
    int pendingIdleHandlerCount = -1; 
    //代表下一個訊息到來前,還需要等待的時長
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands();
        }
        //native層阻塞cpu。如果被阻塞,喚醒事件佇列
        nativePollOnce(ptr, nextPollTimeoutMillis);
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();        
            Message prevMsg = null;
            Message msg = mMessages;

            //如果當前訊息是非同步訊息,都將賦值給prevMsg,過濾掉,直到取到了非非同步訊息
            if (msg != null && msg.target == null) {
              do {
                    prevMsg = msg;
                    msg = msg.next;
              } while (msg != null && !msg.isAsynchronous()); 
            }
            //獲取到了非非同步訊息
            if (msg != null) {
                //任務執行時間大於現在的時間
                if (now < msg.when) {
                //設定下一次輪詢的超時時長
        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    mBlocked = false;//指定為非阻塞任務
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    //設定訊息的使用狀態,即flags |= FLAG_IN_USE
                    msg.markInUse();
                    return msg;   //成功地獲取MessageQueue中的下一條即將要執行的訊息
                }
            } else {
                //表示訊息佇列中無訊息,會一直等待下去
                nextPollTimeoutMillis = -1;
            }
            ......
            //IdleHandler為發現執行緒何時阻塞的回撥介面
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            final IdleHandler idler = mPendingIdleHandlers[i];
            mPendingIdleHandlers[i] = null; //去除handler引用
            boolean keep = false;

        //queueIdle返回true會被空閒的處理器處理,false就會被移走
            try {
                keep = idler.queueIdle();  //idle時執行的方法
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);  //被移走
                }
            }
        }
        //重置idle handler個數為0,保證不會再次重複執行
        pendingIdleHandlerCount = 0;
        nextPollTimeoutMillis = 0;
    }
}

next()方法中,做了非同步Message訊息的判斷,特殊的是這個Message沒有設定target,即msg.target為null。

c)核心的enqueueMessage()方法

boolean enqueueMessage(Message msg, long when) {
    // 每一個普通Message必須有一個target-handler
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    //已在使用狀態
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }
    synchronized (this) {
        //訊息在退出狀態->被回收到訊息池
        if (mQuitting) {  
            msg.recycle();
            return false;
        }
        //標記使用狀態,記錄執行時間
        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        //p為null代表MessageQueue沒有訊息或者msg的觸發時間是佇列中最早的
        if (p == null || when == 0 || when < p.when) {
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked; //當阻塞時需要喚醒
        } else {
            //將訊息按時間順序插入到MessageQueue。
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p;
            prev.next = msg;
        }
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

佇列中的Message觸發時間是有先後順序的。當訊息加入訊息佇列時,會從佇列頭開始遍歷,直到找到訊息應該插入的合適位置,以保證所有訊息的時間順序(內部遍歷佇列中Message,找到when比當前Message的when大的Message,將Message插入到該Message之前,如果沒找到則將Message插入到佇列最後)。一般是當前佇列為空的情況下,next那邊會進入睡眠,需要的時候MessageQueue這邊會喚醒next方法。

d)removeMessages()和removeCallbacksAndMessages()方法

void removeMessages(Handler h, int what, Object object) {
    if (h == null) {
        return;
    }
    synchronized (this) {
        Message p = mMessages;
        //從訊息佇列的頭部開始,移除所有符合條件的訊息
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }
        //移除剩餘的符合要求的訊息
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}



void removeCallbacksAndMessages(Handler h, Object object) {
        if (h == null) {
            return;
        }
        synchronized (this) {
            Message p = mMessages;
            while (p != null && p.target == h
                    && (object == null || p.obj == object)) {
                Message n = p.next;
                mMessages = n;
                p.recycleUnchecked();
                p = n;
            }
            while (p != null) {
                Message n = p.next;
                if (n != null) {
                    if (n.target == h && (object == null || n.obj == object)) {
                        Message nn = n.next;
                        n.recycleUnchecked();
                        p.next = nn;
                        continue;
                    }
                }
                p = n;
            }
        }
}

4)Handler

a)主要引數和構造方法

public class Handler {

   
   final Looper mLooper;          
   final MessageQueue mQueue;   
   final Callback mCallback;    //回撥
   final boolean mAsynchronous;  //是否非同步訊息
   IMessenger mMessenger;

  public interface Callback {
     //如果不需要進一步的處理,則返回True
     public boolean handleMessage(Message msg);
  }

  //有參構造
  public Handler(Looper looper) {
    this(looper, null, false);
  }

    //有參構造
  public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
  }

  public Handler(Callback callback, boolean async) {
    //匿名類、內部類或本地類都必須申明為static,否則會警告可能出現記憶體洩露
    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類中的(ThreadLocal)獲取Looper物件
    mLooper = Looper.myLooper();  
    if (mLooper == null) {
        throw new RuntimeException("");
    }
    mQueue = mLooper.mQueue; //Looper取出訊息佇列
    mCallback = callback;  //回撥
    mAsynchronous = async; //設定訊息是否為非同步處理方式
   }   

b)訊息的傳送:

https://img-blog.csdn.net/20180810163246914?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70

1.post--->呼叫sendMessageDelayed
public final boolean post(Runnable r){
        return  sendMessageDelayed(getPostMessage(r), 0);
}

2.postAtTime--->呼叫sendMessageAtTime
public final boolean postAtTime(Runnable r, long uptimeMillis){
       return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}

3.postAtTime--->呼叫sendMessageAtTime
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

4.postDelayed--->呼叫sendMessageDelayed
public final boolean postDelayed(Runnable r, long delayMillis){
        return sendMessageDelayed(getPostMessage(r), delayMillis);
}

5.postAtFrontOfQueue--->呼叫sendMessageAtFrontOfQueue
public final boolean postAtFrontOfQueue(Runnable r){
        return sendMessageAtFrontOfQueue(getPostMessage(r));
}

6.sendMessage--->呼叫sendMessageDelayed
public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
}

7.sendEmptyMessage--->呼叫sendEmptyMessageDelayed
public final boolean sendEmptyMessage(int what){
        return sendEmptyMessageDelayed(what, 0);
}

8.sendEmptyMessageDelayed--->呼叫sendMessageDelayed
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
}


9.sendEmptyMessageAtTime--->呼叫sendMessageAtTime
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
}

10.sendMessageDelayed--->呼叫sendMessageAtTime
public final boolean sendMessageDelayed(Message msg, long delayMillis){
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

11.sendMessageAtTime--->呼叫enqueueMessage
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
}

12.sendMessageAtFrontOfQueue--->呼叫enqueueMessage
//FIXME 該方法通過設定訊息的觸發時間為0,從而使Message加入到訊息佇列的隊頭
public final boolean sendMessageAtFrontOfQueue(Message msg) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, 0);
}

13.enqueueMessage呼叫MessageQueue中的enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //uptimeMillis為系統當前的執行時間
        return queue.enqueueMessage(msg, uptimeMillis);
}
if (mAsynchronous) {
     msg.setAsynchronous(true);
}

可以看到enqueueMessage方法時,每次都判斷是否是非同步訊息。這就和MessageQueue中的Next()判斷聯絡到了一起。

 

c)訊息的移除--都會呼叫訊息佇列中的移除方法

public final void removeCallbacks(Runnable r){
        mQueue.removeMessages(this, r, null);
}


public final void removeCallbacks(Runnable r, Object token){
        mQueue.removeMessages(this, r, token);
}


public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
}


public final void removeMessages(int what, Object object) {
        mQueue.removeMessages(this, what, object);
}


public final void removeCallbacksAndMessages(Object token) {
        mQueue.removeCallbacksAndMessages(this, token);
}

d)handleMessage(處理訊息)和 dispatchMessage(分發訊息)

    //處理訊息
    public void handleMessage(Message msg) {
    }
    
    //分發訊息
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {

            //當Message存在回撥方法,回撥方法msg.callback.run()
            handleCallback(msg);
        } else {

            //當Handler存在Callback成員變數時,回撥方法mCallback.handleMessage();
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }

            //Handler子類通過覆寫該方法來完成具體的邏輯
            handleMessage(msg);
        }
    }

優先順序:

Message的回撥方法>Handler的回撥方法>Handler的預設方法

6.總結

  1. Handler通過sendMessage()方法傳送Message到MessageQueue佇列
  2. 當前Thread中Looper通過呼叫loop(),不斷取出達到觸發條件的Message,通過對應target(Handler)的dispatchMessage()方法,將Message交給Handler的handleMessage()方法來處理。
  3. 一個執行緒對應一個Looper,一個Looper對應一個MessageQueue,一個MessageQueue可以對用多個Message。但是一個Message只能讓一個handler來處理(就是Message中target所指定的handler)。

 

參考:

handler傳送非同步訊息:https://blog.csdn.net/cdecde111/article/details/54670136

https://blog.csdn.net/woshiluoye9/article/details/72544764

http://gityuan.com/2015/12/26/handler-message-framework/

https://blog.csdn.net/iispring/article/details/47180325

https://blog.csdn.net/milllulei/article/details/80927539

https://www.cnblogs.com/angeldevil/p/3340644.html