1)handler怎么使用會產(chǎn)生內(nèi)存泄露?
1.handler作用:
1)傳遞消息Message
- //2種創(chuàng)建消息方法
- //1.通過handler實例獲取
- Handler handler = new Handler();
- Message message=handler.obtainMessage();
- //2.通過Message獲取
- Message message=Message.obtain();
- //源碼中第一種獲取方式其實也是內(nèi)部調(diào)用了第二種:
- public final Message obtainMessage(){
- return Message.obtain(this);
- }
不建議直接new Message,,Message內(nèi)部保存了一個緩存的消息池,,我們可以用obtain從緩存池獲得一個消息,,Message使用完后系統(tǒng)會調(diào)用recycle回收,,如果自己new很多Message,,每次使用完后系統(tǒng)放入緩存池,,會占用很多內(nèi)存的。
- //傳遞的數(shù)據(jù)
- Bundle bundle = new Bundle();
- bundle.putString("msg", "傳遞我這個消息");
- //發(fā)送數(shù)據(jù)
- Message message = Message.obtain();
- message.setData(bundle); //message.obj=bundle 傳值也行
- message.what = 0x11;
- handler.sendMessage(message);
- //數(shù)據(jù)的接收
- 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
- //創(chuàng)建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();
- //發(fā)送消息
- new Handler().sendMessage(message);
- //延時1s發(fā)送消息
- new Handler().sendMessageDelayed(message, 1000);
- //發(fā)送帶標記的消息(內(nèi)部創(chuàng)建了message,并設(shè)置msg.what = 0x1)
- new Handler().sendEmptyMessage(0x1);
- //延時1s發(fā)送帶標記的消息
- new Handler().sendEmptyMessageDelayed(0x1, 1000);
- //延時1秒發(fā)送消息(第二個參數(shù)為:相對系統(tǒng)開機時間的絕對時間,,而SystemClock.uptimeMillis()是當前開機時間)
- new Handler().sendMessageAtTime(message, SystemClock.uptimeMillis() + 1000);
- //避免內(nèi)存泄露的方法:
- //移除標記為0x1的消息
- new Handler().removeMessages(0x1);
- //移除回調(diào)的消息
- new Handler().removeCallbacks(Runnable);
- //移除回調(diào)和所有message
- new Handler().removeCallbacksAndMessages(null);
3.handler使用避免內(nèi)存泄露
1)handler怎么使用會產(chǎn)生內(nèi)存泄露?
- 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被執(zhí)行時,被延遲的這個消息存于主線程消息隊列中1分鐘,
- //此消息包含handler引用,,而handler由匿名內(nèi)部類創(chuàng)建,持有activity引用,,
- //activity便不能正常銷毀,,從而泄露
- handler.postDelayed(new Runnable() {
- @Override
- public void run() {
- ......
- }
- }, 1000 * 60);
- }
- }
2)如何避免handler的內(nèi)存泄露?
- public class MainActivity extends AppCompatActivity {
- //創(chuàng)建靜態(tài)內(nèi)部類
- 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){
- //執(zhí)行業(yè)務邏輯
- }
- }
- }
- private static final Runnable myRunnable = new Runnable() {
- @Override
- public void run() {
- //執(zhí)行我們的業(yè)務邏輯
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- MyHandler myHandler=new MyHandler(this);
- //延遲5分鐘后發(fā)送
- myHandler.postDelayed(myRunnable, 1000 * 60 * 5);
- }
- }
3) 雷區(qū)
a)Handler.post(Runnable)其實就是生成一個what為0的Message,調(diào)用
myHandler.removeMessages(0);
會使runnable任務從消息隊列中清除。
詳細解釋:https://www.cnblogs.com/coding-way/p/5110125.html(轉(zhuǎn))
b) 子線程直接創(chuàng)建Handler,拋異常Can't create handler inside thread that has not called Looper.prepare()
原因是非主線程沒有l(wèi)oop對象,,所以要調(diào)用Looper.prepare()方法,,而且如果主線程給子線程發(fā)送消息,還要調(diào)用一個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剛好還在處理消息,如果需要用的資源已被釋放,,則會出現(xiàn)空指針異常,。
所以在ondestory中去remove掉我們要處理的事件,還是有必要的,。不想處理就直接try catch或者判空,。
d)有時候你會發(fā)現(xiàn)removeCallbacks會失效,不能從消息隊列中移除,。
出現(xiàn)這情況是activity切入后臺,,再回到前臺,,此時的runnable由于被重定義,就會和原先的runnable并非同一個對象,。所以這么做,,加上static即可
- static Handler handler = new Handler();
- static Runnable myRunnable = new Runnable() {
- @Override
- public void run() {
- //執(zhí)行我們的業(yè)務邏輯
- }
- };
這樣,因為靜態(tài)變量在內(nèi)存中只有一個拷貝,,保證runnable始終是同一個對象,。
4.handlerThread
1) handlerThread是什么?
(題外話:異步存在形式有thread,handlerThead,,asyncTask,線程池,,intentService)
handlerThread繼承thread,不過內(nèi)部比普通線程多了一個Looper
- //內(nèi)部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);
- //創(chuàng)建一個HandlerThread并啟動它
- thread = new HandlerThread("MyHandlerThread");
- thread.start();
- //使用HandlerThread的looper對象創(chuàng)建Handler
- mHandler = new Handler(thread.getLooper(), new Handler.Callback() {
- @Override
- public boolean handleMessage(Message msg) {
- //這個方法是運行在 handler-thread 線程中的,可以執(zhí)行耗時操作,因此不能更新ui,,要注意
- if (msg.what == 0x1) {
- try {
- Thread.sleep(3000);
- Log.e("測試: ", "執(zhí)行了3s的耗時操作");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- //這個方法是運行在 handler-thread 線程中的,可以執(zhí)行耗時操作,因此不能更新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中,只要調(diào)用了
mHandler.sendEmptyMessage(0x1);
就會開始執(zhí)行任務
幾個地方要注意:
a.handleMessage()可以做耗時操作,,但是不能更新ui
b.如果不手動的調(diào)用HandlerThread.quit()或者HandlerThread..quitSafely()方法,,HandlerThread會將持續(xù)的接收新的任務事件。
c.只有handleMessage()方法執(zhí)行完,,這輪的任務才算完成,,HandlerThread才會去執(zhí)行下一個任務。而且在此次執(zhí)行時,,即使手動的去調(diào)用quit()方法,,HandlerThread的此次任務也不會停止。但是,,會停止下輪任務的接收,。
- 舉例:
- //耗時任務換成這個,點擊按鈕執(zhí)行quit()方法,發(fā)現(xiàn)此次任務依舊執(zhí)行
- for (int i = 0; i < 99999999; i++) {
- Log.e("測試: ", "輸出" +i);
- }
d.HandlerThread的2種停止接收事件的方法,。
第一個就是quit(),實際上執(zhí)行了MessageQueue中的removeAllMessagesLocked方法,,該方法的作用是把MessageQueue消息池中所有的消息全部清空,無論是延遲消息(帶Delayed的)還是非延遲消息,。
第二個就是quitSafely(),執(zhí)行了MessageQueue中的removeAllFutureMessagesLocked方法,,該方法只會清空MessageQueue消息池中所有的延遲消息,并將消息池中所有的非延遲消息派發(fā)出去讓Handler去處理,,quitSafely相比于quit方法安全之處在于清空消息之前會派發(fā)所有的非延遲消息,。
- 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方法后,即使發(fā)送新事件,,也不會被接收
- findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- thread.quit();
- //發(fā)送新事件
- mHandler.sendEmptyMessage(0x1);
- }
- );
e.即使多次執(zhí)行mHandler.sendEmptyMessage(0x1),,任務隊列中的任務依然只能一個一個的被處理。上一任務結(jié)束,,開始執(zhí)行下一個,。
- 日志顯示:輸出0-99的任務結(jié)束,,才執(zhí)行下個輸出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.源碼解析
說到源碼,主要還是幾個關(guān)鍵詞,。分別為Message,,Looper,MessageQueue,,Handler,。還有Thread
先說Looper,MessageQueue,,Handler3者關(guān)聯(lián)的思路:
主線程-->prepareMainLooper()(內(nèi)部調(diào)用prepare() ,,去實例化Looper,Looper實例化同時創(chuàng)建了messagequeue,,11對應關(guān)系)-->主線程中的handler獲取當前線程的Looper-->3者關(guān)聯(lián)
- 插播主線程ActivityThread:
- public static void main(String[] args) {
- ......
- Looper.prepareMainLooper();
- ......
- //區(qū)別:子線程是創(chuàng)建handler;
- //主線程是通過getHandler()獲取內(nèi)部類實例
- if(sMainThreadHandler==null){
- sMainThreadHandler=thread.getHandler();
- }
- ......
- }
- private class H extends Handler{
- ......
- }
子線程-->直接通過Looper.prepare()去實例化Looper,,Looper實例化同時創(chuàng)建了messagequeue(11對應關(guān)系) -->實例化Handler同時獲取當前子線程的Looper-->3者關(guān)聯(lián)
1)Message消息
- public final class Message implements Parcelable {
- //用戶定義的消息代碼,以便接收者能夠識別
- public int what;
- //arg1和arg2是使用成本較低的替代品-也可以用來存儲int值
- public int arg1;
- public int arg2;
- //存放任意類型的對象
- public Object obj;
- //消息觸發(fā)時間
- long when;
- //消息攜帶內(nèi)容
- Bundle data;
- //消息響應方
- Handler target;
- //消息管理器,,會關(guān)聯(lián)到一個handler
- public Messanger replyTo;
- //回調(diào)方法
- 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(); //消息池為空-直接創(chuàng)建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,并清空消息所有的參數(shù),。
- 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 (轉(zhuǎn))
- 插播ThreadLocal:
- ThreadLocal是線程的局部變量,, 是每一個線程所單獨持有的,,其他線程不能對其進行訪問。
主線程和子線程中的Looper的初始化
- public final class Looper {
- //內(nèi)部消息隊列MessageQueue
- final MessageQueue mQueue;
- //Looper所在的線程
- final Thread mThread;
- //Looper的變量存儲
- static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
- //主looper
- private static Looper sMainLooper;
- //私有構(gòu)造方法,,不能通過New實例化,。
- private Looper(boolean quitAllowed) {
- mQueue = new MessageQueue(quitAllowed);//創(chuàng)建與其綁定的消息隊列MessageQueue
- mThread = Thread.currentThread(); //綁定當前線程
- }
- //子線程的調(diào)用----->最終通過prepare(boolean)實例化Looper
- public static void prepare() {
- prepare(true);
- }
- //主線程的調(diào)用----->最終通過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();//存儲區(qū)中l(wèi)ooper作為主looper
- }
- }
- public static @Nullable Looper myLooper() {
- return sThreadLocal.get();
- }
- //quitAllowed代表是否允許退出,主線程調(diào)用為不允許退出,,子線程為可退出
- private static void prepare(boolean quitAllowed) {
- if (sThreadLocal.get() != null) {
- //看出一個線程只能存在一個Looper-->則調(diào)用二次Looper.prepare拋出異常
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper(quitAllowed));//Looper的變量存儲+實例化Looper
- }
Loop()方法,,循環(huán)取出messagequeue消息隊列中的消息,并分發(fā)出去,。再把分發(fā)后的Message回收到消息池,,以便重復利用。
- public static void loop() {
- final Looper me = myLooper(); //從存儲區(qū)拿出looper
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- final MessageQueue queue = me.mQueue; //獲取Looper對象中的消息隊列
- ......
- //進入loop的主循環(huán)方法
- for (;;) {
- Message msg = queue.next(); //可能會阻塞
- if (msg == null) { //沒有消息,,則退出循環(huán)
- return;
- }
- ......
- //target是handler,此處用于分發(fā)Message
- msg.target.dispatchMessage(msg);
- ......
- msg.recycleUnchecked(); //將Message放入消息池
- }
- }
Looper中的quit方法-->調(diào)用的還是messageQueue中的quit()
- public void quit() {
- mQueue.quit(false);
- }
3) MessageQueue消息隊列
a)主要參數(shù)和構(gòu)造方法
- 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;
- //構(gòu)造方法
- MessageQueue(boolean quitAllowed) {
- mQuitAllowed = quitAllowed;
- mPtr = nativeInit(); //通過native方法初始化消息隊列,,其中mPtr是供native代碼使用
- }
b)核心的next()方法
- //不停提取下一條message
- Message next() {
- final long ptr = mPtr;
- //判斷是否退出消息循環(huán)
- 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) {
- //任務執(zhí)行時間大于現(xiàn)在的時間
- if (now < msg.when) {
- //設(shè)置下一次輪詢的超時時長
- 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;
- //設(shè)置消息的使用狀態(tài),即flags |= FLAG_IN_USE
- msg.markInUse();
- return msg; //成功地獲取MessageQueue中的下一條即將要執(zhí)行的消息
- }
- } else {
- //表示消息隊列中無消息,,會一直等待下去
- nextPollTimeoutMillis = -1;
- }
- ......
- //IdleHandler為發(fā)現(xiàn)線程何時阻塞的回調(diào)接口
- 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時執(zhí)行的方法
- } catch (Throwable t) {
- Log.wtf(TAG, "IdleHandler threw exception", t);
- }
- if (!keep) {
- synchronized (this) {
- mIdleHandlers.remove(idler); //被移走
- }
- }
- }
- //重置idle handler個數(shù)為0,保證不會再次重復運行
- pendingIdleHandlerCount = 0;
- nextPollTimeoutMillis = 0;
- }
- }
next()方法中,做了異步Message消息的判斷,特殊的是這個Message沒有設(shè)置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.");
- }
- //已在使用狀態(tài)
- if (msg.isInUse()) {
- throw new IllegalStateException(msg + " This message is already in use.");
- }
- synchronized (this) {
- //消息在退出狀態(tài)->被回收到消息池
- if (mQuitting) {
- msg.recycle();
- return false;
- }
- //標記使用狀態(tài),記錄執(zhí)行時間
- msg.markInUse();
- msg.when = when;
- Message p = mMessages;
- boolean needWake;
- //p為null代表MessageQueue沒有消息或者msg的觸發(fā)時間是隊列中最早的
- 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觸發(fā)時間是有先后順序的,。當消息加入消息隊列時,,會從隊列頭開始遍歷,直到找到消息應該插入的合適位置,,以保證所有消息的時間順序(內(nèi)部遍歷隊列中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)主要參數(shù)和構(gòu)造方法
- public class Handler {
- final Looper mLooper;
- final MessageQueue mQueue;
- final Callback mCallback; //回調(diào)
- final boolean mAsynchronous; //是否異步消息
- IMessenger mMessenger;
- public interface Callback {
- //如果不需要進一步的處理,,則返回True
- public boolean handleMessage(Message msg);
- }
- //有參構(gòu)造
- public Handler(Looper looper) {
- this(looper, null, false);
- }
- //有參構(gòu)造
- public Handler(Looper looper, Callback callback, boolean async) {
- mLooper = looper;
- mQueue = looper.mQueue;
- mCallback = callback;
- mAsynchronous = async;
- }
- public Handler(Callback callback, boolean async) {
- //匿名類,、內(nèi)部類或本地類都必須申明為static,否則會警告可能出現(xiàn)內(nèi)存泄露
- 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; //回調(diào)
- mAsynchronous = async; //設(shè)置消息是否為異步處理方式
- }
b)消息的發(fā)送:
- 1.post--->調(diào)用sendMessageDelayed
- public final boolean post(Runnable r){
- return sendMessageDelayed(getPostMessage(r), 0);
- }
- 2.postAtTime--->調(diào)用sendMessageAtTime
- public final boolean postAtTime(Runnable r, long uptimeMillis){
- return sendMessageAtTime(getPostMessage(r), uptimeMillis);
- }
- 3.postAtTime--->調(diào)用sendMessageAtTime
- public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){
- return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
- }
- 4.postDelayed--->調(diào)用sendMessageDelayed
- public final boolean postDelayed(Runnable r, long delayMillis){
- return sendMessageDelayed(getPostMessage(r), delayMillis);
- }
- 5.postAtFrontOfQueue--->調(diào)用sendMessageAtFrontOfQueue
- public final boolean postAtFrontOfQueue(Runnable r){
- return sendMessageAtFrontOfQueue(getPostMessage(r));
- }
- 6.sendMessage--->調(diào)用sendMessageDelayed
- public final boolean sendMessage(Message msg){
- return sendMessageDelayed(msg, 0);
- }
- 7.sendEmptyMessage--->調(diào)用sendEmptyMessageDelayed
- public final boolean sendEmptyMessage(int what){
- return sendEmptyMessageDelayed(what, 0);
- }
- 8.sendEmptyMessageDelayed--->調(diào)用sendMessageDelayed
- public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
- Message msg = Message.obtain();
- msg.what = what;
- return sendMessageDelayed(msg, delayMillis);
- }
- 9.sendEmptyMessageAtTime--->調(diào)用sendMessageAtTime
- public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
- Message msg = Message.obtain();
- msg.what = what;
- return sendMessageAtTime(msg, uptimeMillis);
- }
- 10.sendMessageDelayed--->調(diào)用sendMessageAtTime
- public final boolean sendMessageDelayed(Message msg, long delayMillis){
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
- 11.sendMessageAtTime--->調(diào)用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--->調(diào)用enqueueMessage
- //FIXME 該方法通過設(shè)置消息的觸發(fā)時間為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調(diào)用MessageQueue中的enqueueMessage
- private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
- msg.target = this;
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
- //uptimeMillis為系統(tǒng)當前的運行時間
- return queue.enqueueMessage(msg, uptimeMillis);
- }
- if (mAsynchronous) {
- msg.setAsynchronous(true);
- }
可以看到enqueueMessage方法時,每次都判斷是否是異步消息,。這就和MessageQueue中的Next()判斷聯(lián)系到了一起。
c)消息的移除--都會調(diào)用消息隊列中的移除方法
- 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(分發(fā)消息)
- //處理消息
- public void handleMessage(Message msg) {
- }
- //分發(fā)消息
- public void dispatchMessage(Message msg) {
- if (msg.callback != null) {
- //當Message存在回調(diào)方法,,回調(diào)方法msg.callback.run()
- handleCallback(msg);
- } else {
- //當Handler存在Callback成員變量時,,回調(diào)方法mCallback.handleMessage();
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {
- return;
- }
- }
- //Handler子類通過覆寫該方法來完成具體的邏輯
- handleMessage(msg);
- }
- }
優(yōu)先級:
Message的回調(diào)方法>Handler的回調(diào)方法>Handler的默認方法
6.總結(jié)
- Handler通過sendMessage()方法發(fā)送Message到MessageQueue隊列
- 當前Thread中Looper通過調(diào)用loop(),,不斷取出達到觸發(fā)條件的Message,,通過對應target(Handler)的dispatchMessage()方法,將Message交給Handler的handleMessage()方法來處理。
- 一個線程對應一個Looper,,一個Looper對應一個MessageQueue,,一個MessageQueue可以對用多個Message。但是一個Message只能讓一個handler來處理(就是Message中target所指定的handler),。
參考:
handler發(fā)送異步消息:https://blog.csdn.net/cdecde111/article/details/54670136
https://blog.csdn.net/woshiluoye9/article/details/72544764
http:///2015/12/26/handler-message-framework/
https://blog.csdn.net/iispring/article/details/47180325