Handler用法及解析
目錄
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)訊息的傳送:
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.總結
- Handler通過sendMessage()方法傳送Message到MessageQueue佇列
- 當前Thread中Looper通過呼叫loop(),不斷取出達到觸發條件的Message,通過對應target(Handler)的dispatchMessage()方法,將Message交給Handler的handleMessage()方法來處理。
- 一個執行緒對應一個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