久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Handler用法及解析

 戴維圖書館 2019-12-28

Handler用法及解析

原創(chuàng) 魔法少女 厄加特 發(fā)布于2018-08-10 17:01:12 閱讀數(shù) 15421 收藏
分類專欄: android源碼分析
版權(quán)聲明:本文為博主原創(chuàng)文章,,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,,轉(zhuǎn)載請附上原文出處鏈接和本聲明,。
目錄

1.handler作用: 

1)傳遞消息Message

2)子線程通知主線程更新ui

2.常用api

3.handler使用避免內(nèi)存泄露

 1)handler怎么使用會產(chǎn)生內(nèi)存泄露?

 2)如何避免handler的內(nèi)存泄露?

 3)  雷區(qū)

4.handlerThread

1)  handlerThread是什么?

2)HandlerThread使用及銷毀

5.源碼解析

1)Message消息

2)Looper

3)  MessageQueue消息隊列

4)Handler

6.總結(jié)


1.handler作用: 

1)傳遞消息Message

  1. //2種創(chuàng)建消息方法
  2. //1.通過handler實例獲取
  3. Handler handler = new Handler();
  4. Message message=handler.obtainMessage();
  5. //2.通過Message獲取
  6. Message message=Message.obtain();
  7. //源碼中第一種獲取方式其實也是內(nèi)部調(diào)用了第二種:
  8. public final Message obtainMessage(){
  9. return Message.obtain(this);
  10. }

不建議直接new Message,,Message內(nèi)部保存了一個緩存的消息池,,我們可以用obtain從緩存池獲得一個消息,,Message使用完后系統(tǒng)會調(diào)用recycle回收,,如果自己new很多Message,,每次使用完后系統(tǒng)放入緩存池,,會占用很多內(nèi)存的。 

  1. //傳遞的數(shù)據(jù)
  2. Bundle bundle = new Bundle();
  3. bundle.putString("msg", "傳遞我這個消息");
  4. //發(fā)送數(shù)據(jù)
  5. Message message = Message.obtain();
  6. message.setData(bundle); //message.obj=bundle 傳值也行
  7. message.what = 0x11;
  8. handler.sendMessage(message);
  9. //數(shù)據(jù)的接收
  10. final Handler handler = new Handler() {
  11. @Override
  12. public void handleMessage(Message msg) {
  13. super.handleMessage(msg);
  14. if (msg.what == 0x11) {
  15. Bundle bundle = msg.getData();
  16. String date = bundle.getString("msg");
  17. }
  18. }
  19. };

2)子線程通知主線程更新ui

  1. //創(chuàng)建handler
  2. final Handler handler = new Handler() {
  3. @Override
  4. public void handleMessage(Message msg) {
  5. super.handleMessage(msg);
  6. if (msg.what == 0x11) {
  7. //更新ui
  8. ......
  9. }
  10. }
  11. };
  12. new Thread(new Runnable() {
  13. @Override
  14. public void run() {
  15. //FIXME 這里直接更新ui是不行的
  16. //還有其他更新ui方式,runOnUiThread()等
  17. message.what = 0x11;
  18. handler.sendMessage(message);
  19. }
  20. }).start();

2.常用api

  1. //消息
  2. Message message = Message.obtain();
  3. //發(fā)送消息
  4. new Handler().sendMessage(message);
  5. //延時1s發(fā)送消息
  6. new Handler().sendMessageDelayed(message, 1000);
  7. //發(fā)送帶標記的消息(內(nèi)部創(chuàng)建了message,并設(shè)置msg.what = 0x1)
  8. new Handler().sendEmptyMessage(0x1);
  9. //延時1s發(fā)送帶標記的消息
  10. new Handler().sendEmptyMessageDelayed(0x1, 1000);
  11. //延時1秒發(fā)送消息(第二個參數(shù)為:相對系統(tǒng)開機時間的絕對時間,,而SystemClock.uptimeMillis()是當前開機時間)
  12. new Handler().sendMessageAtTime(message, SystemClock.uptimeMillis() + 1000);
  13. //避免內(nèi)存泄露的方法:
  14. //移除標記為0x1的消息
  15. new Handler().removeMessages(0x1);
  16. //移除回調(diào)的消息
  17. new Handler().removeCallbacks(Runnable);
  18. //移除回調(diào)和所有message
  19. new Handler().removeCallbacksAndMessages(null);

3.handler使用避免內(nèi)存泄露

 1)handler怎么使用會產(chǎn)生內(nèi)存泄露?

  1. public class MainActivity extends AppCompatActivity {
  2. final Handler handler = new Handler() {
  3. @Override
  4. public void handleMessage(Message msg) {
  5. super.handleMessage(msg);
  6. ......
  7. }
  8. };
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_main);
  13. //activity被執(zhí)行時,被延遲的這個消息存于主線程消息隊列中1分鐘,
  14. //此消息包含handler引用,,而handler由匿名內(nèi)部類創(chuàng)建,持有activity引用,,
  15. //activity便不能正常銷毀,,從而泄露
  16. handler.postDelayed(new Runnable() {
  17. @Override
  18. public void run() {
  19. ......
  20. }
  21. }, 1000 * 60);
  22. }
  23. }

 2)如何避免handler的內(nèi)存泄露?

  1. public class MainActivity extends AppCompatActivity {
  2. //創(chuàng)建靜態(tài)內(nèi)部類
  3. private static class MyHandler extends Handler{
  4. //持有弱引用MainActivity,GC回收時會被回收掉.
  5. private final WeakReference<MainActivity> mAct;
  6. public MyHandler(MainActivity mainActivity){
  7. mAct =new WeakReference<MainActivity>(mainActivity);
  8. }
  9. @Override
  10. public void handleMessage(Message msg) {
  11. MainActivity mainAct=mAct.get();
  12. super.handleMessage(msg);
  13. if(mainAct!=null){
  14. //執(zhí)行業(yè)務邏輯
  15. }
  16. }
  17. }
  18. private static final Runnable myRunnable = new Runnable() {
  19. @Override
  20. public void run() {
  21. //執(zhí)行我們的業(yè)務邏輯
  22. }
  23. };
  24. @Override
  25. protected void onCreate(Bundle savedInstanceState) {
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.activity_main);
  28. MyHandler myHandler=new MyHandler(this);
  29. //延遲5分鐘后發(fā)送
  30. myHandler.postDelayed(myRunnable, 1000 * 60 * 5);
  31. }
  32. }

 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()的方法(此方法保證消息隊列中的消息被不停的拿出,,并被處理)

  1. class MyThread extends Thread{
  2. @Override
  3. public void run() {
  4. super.run();
  5. Looper.prepare();
  6. Handler handler = new Handler() {
  7. @Override
  8. public void handleMessage(Message msg) {
  9. super.handleMessage(msg);
  10. //處理消息
  11. }
  12. };
  13. Looper.loop();
  14. }
  15. }

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

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

d)有時候你會發(fā)現(xiàn)removeCallbacks會失效,不能從消息隊列中移除,。

出現(xiàn)這情況是activity切入后臺,,再回到前臺,,此時的runnable由于被重定義,就會和原先的runnable并非同一個對象,。所以這么做,,加上static即可

  1. static Handler handler = new Handler();
  2. static Runnable myRunnable = new Runnable() {
  3. @Override
  4. public void run() {
  5. //執(zhí)行我們的業(yè)務邏輯
  6. }
  7. };

這樣,因為靜態(tài)變量在內(nèi)存中只有一個拷貝,,保證runnable始終是同一個對象,。

4.handlerThread

1)  handlerThread是什么?

(題外話:異步存在形式有thread,handlerThead,,asyncTask,線程池,,intentService)

handlerThread繼承thread,不過內(nèi)部比普通線程多了一個Looper

  1. //內(nèi)部Looper.prepare()
  2. @Override
  3. public void run() {
  4. mTid = Process.myTid();
  5. Looper.prepare();
  6. synchronized (this) {
  7. mLooper = Looper.myLooper();
  8. notifyAll();
  9. }
  10. Process.setThreadPriority(mPriority);
  11. onLooperPrepared();
  12. Looper.loop();
  13. mTid = -1;
  14. }

2)HandlerThread使用及銷毀

  1. public class MainActivity extends AppCompatActivity {
  2. private HandlerThread thread;
  3. static Handler mHandler;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. //創(chuàng)建一個HandlerThread并啟動它
  9. thread = new HandlerThread("MyHandlerThread");
  10. thread.start();
  11. //使用HandlerThread的looper對象創(chuàng)建Handler
  12. mHandler = new Handler(thread.getLooper(), new Handler.Callback() {
  13. @Override
  14. public boolean handleMessage(Message msg) {
  15. //這個方法是運行在 handler-thread 線程中的,可以執(zhí)行耗時操作,因此不能更新ui,,要注意
  16. if (msg.what == 0x1) {
  17. try {
  18. Thread.sleep(3000);
  19. Log.e("測試: ", "執(zhí)行了3s的耗時操作");
  20. } catch (InterruptedException e) {
  21. e.printStackTrace();
  22. }
  23. //這個方法是運行在 handler-thread 線程中的,可以執(zhí)行耗時操作,因此不能更新ui,,要注意
  24. // ((Button) MainActivity.this.findViewById(R.id.button)).setText("hello");
  25. }
  26. return false;
  27. }
  28. });
  29. //停止handlerthread接收事件
  30. findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
  31. @Override
  32. public void onClick(View v) {
  33. thread.quit();
  34. }
  35. });
  36. //運行
  37. mHandler.sendEmptyMessage(0x1);
  38. }
  39. }

上面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的此次任務也不會停止。但是,,會停止下輪任務的接收,。

  1. 舉例:
  2. //耗時任務換成這個,點擊按鈕執(zhí)行quit()方法,發(fā)現(xiàn)此次任務依舊執(zhí)行
  3. for (int i = 0; i < 99999999; i++) {
  4. Log.e("測試: ", "輸出" +i);
  5. }

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

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

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

  1. MessageQueue中源碼:
  2. void quit(boolean safe) {
  3. if (!mQuitAllowed) {
  4. throw new IllegalStateException("Main thread not allowed to quit.");
  5. }
  6. synchronized (this) {
  7. if (mQuitting) {
  8. return;
  9. }
  10. mQuitting = true;
  11. if (safe) {
  12. removeAllFutureMessagesLocked();
  13. } else {
  14. removeAllMessagesLocked();
  15. }
  16. // We can assume mPtr != 0 because mQuitting was previously false.
  17. nativeWake(mPtr);
  18. }
  19. }
  1. 舉例:
  2. //quit方法后,即使發(fā)送新事件,,也不會被接收
  3. findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
  4. @Override
  5. public void onClick(View v) {
  6. thread.quit();
  7. //發(fā)送新事件
  8. mHandler.sendEmptyMessage(0x1);
  9. }
  10. );

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

  1. 日志顯示:輸出0-99的任務結(jié)束,,才執(zhí)行下個輸出0-99的任務
  2. 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出95
  3. 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出96
  4. 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出97
  5. 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出98
  6. 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/測試:: 輸出99
  7. 08-09 20:17:05.718 12618-12762/com.bihucj.mcandroid E/測試:: 輸出0
  8. 08-09 20:17:05.718 12618-12762/com.bihucj.mcandroid E/測試:: 輸出1
  9. 08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/測試:: 輸出2
  10. 08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/測試:: 輸出3
  11. 08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/測試:: 輸出4
  12. 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)

  1. 插播主線程ActivityThread:
  2. public static void main(String[] args) {
  3. ......
  4. Looper.prepareMainLooper();
  5. ......
  6. //區(qū)別:子線程是創(chuàng)建handler;
  7. //主線程是通過getHandler()獲取內(nèi)部類實例
  8. if(sMainThreadHandler==null){
  9. sMainThreadHandler=thread.getHandler();
  10. }
  11. ......
  12. }
  13. private class H extends Handler{
  14. ......
  15. }

子線程-->直接通過Looper.prepare()去實例化Looper,,Looper實例化同時創(chuàng)建了messagequeue(11對應關(guān)系) -->實例化Handler同時獲取當前子線程的Looper-->3者關(guān)聯(lián)

1)Message消息

  1. public final class Message implements Parcelable {
  2. //用戶定義的消息代碼,以便接收者能夠識別
  3. public int what;
  4. //arg1和arg2是使用成本較低的替代品-也可以用來存儲int值
  5. public int arg1;
  6. public int arg2;
  7. //存放任意類型的對象
  8. public Object obj;
  9. //消息觸發(fā)時間
  10. long when;
  11. //消息攜帶內(nèi)容
  12. Bundle data;
  13. //消息響應方
  14. Handler target;
  15. //消息管理器,,會關(guān)聯(lián)到一個handler
  16. public Messanger replyTo;
  17. //回調(diào)方法
  18. Runnable callback;
  19. //消息存儲的鏈表,。這樣sPool就成為了一個Messages的緩存鏈表。
  20. Message next;
  21. //消息池
  22. private static Message sPool;
  23. //消息池的默認大小
  24. private static final int MAX_POOL_SIZE = 50;
  25. //從消息池中獲取消息
  26. public static Message obtain() {
  27. synchronized (sPoolSync) {
  28. if (sPool != null) {
  29. Message m = sPool; //從sPool的表頭拿出Message
  30. sPool = m.next; //將消息池的表頭指向下一個Message
  31. m.next = null; //將取出消息的鏈表斷開
  32. m.flags = 0; // 清除flag----flag標記判斷此消息是否正被使用(下方isInUse方法)
  33. sPoolSize--; //消息池可用大小進行減1
  34. return m;
  35. }
  36. }
  37. return new Message(); //消息池為空-直接創(chuàng)建Message
  38. }
  39. //通過標記判斷消息是否正被使用
  40. boolean isInUse() {
  41. return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
  42. }
  43. //5.0后為true,之前為false.
  44. private static boolean gCheckRecycle = true;
  45. public void recycle() {
  46. if (isInUse()) {
  47. if (gCheckRecycle) {
  48. throw new IllegalStateException("This message cannot be recycled because it is still in use.");
  49. }
  50. return;
  51. }
  52. recycleUnchecked(); //消息沒在使用,,回收
  53. }
  54. //對于不再使用的消息,,加入到消息池
  55. void recycleUnchecked() {
  56. //將消息標示位置為IN_USE,并清空消息所有的參數(shù),。
  57. flags = FLAG_IN_USE;
  58. what = 0;
  59. arg1 = 0;
  60. arg2 = 0;
  61. obj = null;
  62. replyTo = null;
  63. sendingUid = -1;
  64. when = 0;
  65. target = null;
  66. callback = null;
  67. data = null;
  68. synchronized (sPoolSync) {
  69. if (sPoolSize < MAX_POOL_SIZE) {
  70. next = sPool;
  71. sPool = this; //當消息池沒有滿時,,將Message加入消息池
  72. sPoolSize++; //消息池可用大小加1
  73. }
  74. }
  75. }

2)Looper

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

  1. 插播ThreadLocal:
  2. ThreadLocal是線程的局部變量,, 是每一個線程所單獨持有的,,其他線程不能對其進行訪問。

主線程和子線程中的Looper的初始化

  1. public final class Looper {
  2. //內(nèi)部消息隊列MessageQueue
  3. final MessageQueue mQueue;
  4. //Looper所在的線程
  5. final Thread mThread;
  6. //Looper的變量存儲
  7. static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
  8. //主looper
  9. private static Looper sMainLooper;
  10. //私有構(gòu)造方法,,不能通過New實例化,。
  11. private Looper(boolean quitAllowed) {
  12. mQueue = new MessageQueue(quitAllowed);//創(chuàng)建與其綁定的消息隊列MessageQueue
  13. mThread = Thread.currentThread(); //綁定當前線程
  14. }
  15. //子線程的調(diào)用----->最終通過prepare(boolean)實例化Looper
  16. public static void prepare() {
  17. prepare(true);
  18. }
  19. //主線程的調(diào)用----->最終通過prepare(boolean)實例化Looper
  20. public static void prepareMainLooper() {
  21. prepare(false);
  22. synchronized (Looper.class) {
  23. if (sMainLooper != null) {
  24. throw new IllegalStateException("The main Looper has already been prepared.");
  25. }
  26. sMainLooper = myLooper();//存儲區(qū)中l(wèi)ooper作為主looper
  27. }
  28. }
  29. public static @Nullable Looper myLooper() {
  30. return sThreadLocal.get();
  31. }
  32. //quitAllowed代表是否允許退出,主線程調(diào)用為不允許退出,,子線程為可退出
  33. private static void prepare(boolean quitAllowed) {
  34. if (sThreadLocal.get() != null) {
  35. //看出一個線程只能存在一個Looper-->則調(diào)用二次Looper.prepare拋出異常
  36. throw new RuntimeException("Only one Looper may be created per thread");
  37. }
  38. sThreadLocal.set(new Looper(quitAllowed));//Looper的變量存儲+實例化Looper
  39. }

Loop()方法,,循環(huán)取出messagequeue消息隊列中的消息,并分發(fā)出去,。再把分發(fā)后的Message回收到消息池,,以便重復利用。

  1. public static void loop() {
  2. final Looper me = myLooper(); //從存儲區(qū)拿出looper
  3. if (me == null) {
  4. throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
  5. }
  6. final MessageQueue queue = me.mQueue; //獲取Looper對象中的消息隊列
  7. ......
  8. //進入loop的主循環(huán)方法
  9. for (;;) {
  10. Message msg = queue.next(); //可能會阻塞
  11. if (msg == null) { //沒有消息,,則退出循環(huán)
  12. return;
  13. }
  14. ......
  15. //target是handler,此處用于分發(fā)Message
  16. msg.target.dispatchMessage(msg);
  17. ......
  18. msg.recycleUnchecked(); //將Message放入消息池
  19. }
  20. }

Looper中的quit方法-->調(diào)用的還是messageQueue中的quit()

  1. public void quit() {
  2. mQueue.quit(false);
  3. }

3)  MessageQueue消息隊列

a)主要參數(shù)和構(gòu)造方法

  1. public final class MessageQueue {
  2. //供native代碼使用
  3. @SuppressWarnings("unused")
  4. private long mPtr;
  5. //交給native層來處理的核心方法
  6. private native static long nativeInit();
  7. private native static void nativeDestroy(long ptr);
  8. private native void nativePollOnce(long ptr, int timeoutMillis); //阻塞操作
  9. private native static void nativeWake(long ptr);
  10. private native static boolean nativeIsPolling(long ptr);
  11. private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
  12. Message mMessages;
  13. //消息隊列是否可以退出
  14. private final boolean mQuitAllowed;
  15. //構(gòu)造方法
  16. MessageQueue(boolean quitAllowed) {
  17. mQuitAllowed = quitAllowed;
  18. mPtr = nativeInit(); //通過native方法初始化消息隊列,,其中mPtr是供native代碼使用
  19. }

b)核心的next()方法

  1. //不停提取下一條message
  2. Message next() {
  3. final long ptr = mPtr;
  4. //判斷是否退出消息循環(huán)
  5. if (ptr == 0) {
  6. return null;
  7. }
  8. int pendingIdleHandlerCount = -1;
  9. //代表下一個消息到來前,還需要等待的時長
  10. int nextPollTimeoutMillis = 0;
  11. for (;;) {
  12. if (nextPollTimeoutMillis != 0) {
  13. Binder.flushPendingCommands();
  14. }
  15. //native層阻塞cpu,。如果被阻塞,,喚醒事件隊列
  16. nativePollOnce(ptr, nextPollTimeoutMillis);
  17. synchronized (this) {
  18. final long now = SystemClock.uptimeMillis();
  19. Message prevMsg = null;
  20. Message msg = mMessages;
  21. //如果當前消息是異步消息,都將賦值給prevMsg,,過濾掉,直到取到了非異步消息
  22. if (msg != null && msg.target == null) {
  23. do {
  24. prevMsg = msg;
  25. msg = msg.next;
  26. } while (msg != null && !msg.isAsynchronous());
  27. }
  28. //獲取到了非異步消息
  29. if (msg != null) {
  30. //任務執(zhí)行時間大于現(xiàn)在的時間
  31. if (now < msg.when) {
  32. //設(shè)置下一次輪詢的超時時長
  33. nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
  34. } else {
  35. mBlocked = false;//指定為非阻塞任務
  36. if (prevMsg != null) {
  37. prevMsg.next = msg.next;
  38. } else {
  39. mMessages = msg.next;
  40. }
  41. msg.next = null;
  42. //設(shè)置消息的使用狀態(tài),即flags |= FLAG_IN_USE
  43. msg.markInUse();
  44. return msg; //成功地獲取MessageQueue中的下一條即將要執(zhí)行的消息
  45. }
  46. } else {
  47. //表示消息隊列中無消息,,會一直等待下去
  48. nextPollTimeoutMillis = -1;
  49. }
  50. ......
  51. //IdleHandler為發(fā)現(xiàn)線程何時阻塞的回調(diào)接口
  52. for (int i = 0; i < pendingIdleHandlerCount; i++) {
  53. final IdleHandler idler = mPendingIdleHandlers[i];
  54. mPendingIdleHandlers[i] = null; //去除handler引用
  55. boolean keep = false;
  56. //queueIdle返回true會被空閑的處理器處理,,false就會被移走
  57. try {
  58. keep = idler.queueIdle(); //idle時執(zhí)行的方法
  59. } catch (Throwable t) {
  60. Log.wtf(TAG, "IdleHandler threw exception", t);
  61. }
  62. if (!keep) {
  63. synchronized (this) {
  64. mIdleHandlers.remove(idler); //被移走
  65. }
  66. }
  67. }
  68. //重置idle handler個數(shù)為0,保證不會再次重復運行
  69. pendingIdleHandlerCount = 0;
  70. nextPollTimeoutMillis = 0;
  71. }
  72. }

next()方法中,做了異步Message消息的判斷,特殊的是這個Message沒有設(shè)置target,,即msg.target為null,。

c)核心的enqueueMessage()方法

  1. boolean enqueueMessage(Message msg, long when) {
  2. // 每一個普通Message必須有一個target-handler
  3. if (msg.target == null) {
  4. throw new IllegalArgumentException("Message must have a target.");
  5. }
  6. //已在使用狀態(tài)
  7. if (msg.isInUse()) {
  8. throw new IllegalStateException(msg + " This message is already in use.");
  9. }
  10. synchronized (this) {
  11. //消息在退出狀態(tài)->被回收到消息池
  12. if (mQuitting) {
  13. msg.recycle();
  14. return false;
  15. }
  16. //標記使用狀態(tài),記錄執(zhí)行時間
  17. msg.markInUse();
  18. msg.when = when;
  19. Message p = mMessages;
  20. boolean needWake;
  21. //p為null代表MessageQueue沒有消息或者msg的觸發(fā)時間是隊列中最早的
  22. if (p == null || when == 0 || when < p.when) {
  23. msg.next = p;
  24. mMessages = msg;
  25. needWake = mBlocked; //當阻塞時需要喚醒
  26. } else {
  27. //將消息按時間順序插入到MessageQueue。
  28. needWake = mBlocked && p.target == null && msg.isAsynchronous();
  29. Message prev;
  30. for (;;) {
  31. prev = p;
  32. p = p.next;
  33. if (p == null || when < p.when) {
  34. break;
  35. }
  36. if (needWake && p.isAsynchronous()) {
  37. needWake = false;
  38. }
  39. }
  40. msg.next = p;
  41. prev.next = msg;
  42. }
  43. if (needWake) {
  44. nativeWake(mPtr);
  45. }
  46. }
  47. return true;
  48. }

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

d)removeMessages()和removeCallbacksAndMessages()方法

  1. void removeMessages(Handler h, int what, Object object) {
  2. if (h == null) {
  3. return;
  4. }
  5. synchronized (this) {
  6. Message p = mMessages;
  7. //從消息隊列的頭部開始,移除所有符合條件的消息
  8. while (p != null && p.target == h && p.what == what
  9. && (object == null || p.obj == object)) {
  10. Message n = p.next;
  11. mMessages = n;
  12. p.recycleUnchecked();
  13. p = n;
  14. }
  15. //移除剩余的符合要求的消息
  16. while (p != null) {
  17. Message n = p.next;
  18. if (n != null) {
  19. if (n.target == h && n.what == what
  20. && (object == null || n.obj == object)) {
  21. Message nn = n.next;
  22. n.recycleUnchecked();
  23. p.next = nn;
  24. continue;
  25. }
  26. }
  27. p = n;
  28. }
  29. }
  30. }
  31. void removeCallbacksAndMessages(Handler h, Object object) {
  32. if (h == null) {
  33. return;
  34. }
  35. synchronized (this) {
  36. Message p = mMessages;
  37. while (p != null && p.target == h
  38. && (object == null || p.obj == object)) {
  39. Message n = p.next;
  40. mMessages = n;
  41. p.recycleUnchecked();
  42. p = n;
  43. }
  44. while (p != null) {
  45. Message n = p.next;
  46. if (n != null) {
  47. if (n.target == h && (object == null || n.obj == object)) {
  48. Message nn = n.next;
  49. n.recycleUnchecked();
  50. p.next = nn;
  51. continue;
  52. }
  53. }
  54. p = n;
  55. }
  56. }
  57. }

4)Handler

a)主要參數(shù)和構(gòu)造方法

  1. public class Handler {
  2. final Looper mLooper;
  3. final MessageQueue mQueue;
  4. final Callback mCallback; //回調(diào)
  5. final boolean mAsynchronous; //是否異步消息
  6. IMessenger mMessenger;
  7. public interface Callback {
  8. //如果不需要進一步的處理,,則返回True
  9. public boolean handleMessage(Message msg);
  10. }
  11. //有參構(gòu)造
  12. public Handler(Looper looper) {
  13. this(looper, null, false);
  14. }
  15. //有參構(gòu)造
  16. public Handler(Looper looper, Callback callback, boolean async) {
  17. mLooper = looper;
  18. mQueue = looper.mQueue;
  19. mCallback = callback;
  20. mAsynchronous = async;
  21. }
  22. public Handler(Callback callback, boolean async) {
  23. //匿名類,、內(nèi)部類或本地類都必須申明為static,否則會警告可能出現(xiàn)內(nèi)存泄露
  24. if (FIND_POTENTIAL_LEAKS) {
  25. final Class<? extends Handler> klass = getClass();
  26. if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
  27. (klass.getModifiers() & Modifier.STATIC) == 0) {
  28. Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
  29. klass.getCanonicalName());
  30. }
  31. }
  32. //從Looper類中的(ThreadLocal)獲取Looper對象
  33. mLooper = Looper.myLooper();
  34. if (mLooper == null) {
  35. throw new RuntimeException("");
  36. }
  37. mQueue = mLooper.mQueue; //Looper取出消息隊列
  38. mCallback = callback; //回調(diào)
  39. mAsynchronous = async; //設(shè)置消息是否為異步處理方式
  40. }

b)消息的發(fā)送:

http://image109.360doc.com/DownloadImg/2019/12/2815/179046646_1_20191228033019456

  1. 1.post--->調(diào)用sendMessageDelayed
  2. public final boolean post(Runnable r){
  3. return sendMessageDelayed(getPostMessage(r), 0);
  4. }
  5. 2.postAtTime--->調(diào)用sendMessageAtTime
  6. public final boolean postAtTime(Runnable r, long uptimeMillis){
  7. return sendMessageAtTime(getPostMessage(r), uptimeMillis);
  8. }
  9. 3.postAtTime--->調(diào)用sendMessageAtTime
  10. public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){
  11. return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
  12. }
  13. 4.postDelayed--->調(diào)用sendMessageDelayed
  14. public final boolean postDelayed(Runnable r, long delayMillis){
  15. return sendMessageDelayed(getPostMessage(r), delayMillis);
  16. }
  17. 5.postAtFrontOfQueue--->調(diào)用sendMessageAtFrontOfQueue
  18. public final boolean postAtFrontOfQueue(Runnable r){
  19. return sendMessageAtFrontOfQueue(getPostMessage(r));
  20. }
  21. 6.sendMessage--->調(diào)用sendMessageDelayed
  22. public final boolean sendMessage(Message msg){
  23. return sendMessageDelayed(msg, 0);
  24. }
  25. 7.sendEmptyMessage--->調(diào)用sendEmptyMessageDelayed
  26. public final boolean sendEmptyMessage(int what){
  27. return sendEmptyMessageDelayed(what, 0);
  28. }
  29. 8.sendEmptyMessageDelayed--->調(diào)用sendMessageDelayed
  30. public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
  31. Message msg = Message.obtain();
  32. msg.what = what;
  33. return sendMessageDelayed(msg, delayMillis);
  34. }
  35. 9.sendEmptyMessageAtTime--->調(diào)用sendMessageAtTime
  36. public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
  37. Message msg = Message.obtain();
  38. msg.what = what;
  39. return sendMessageAtTime(msg, uptimeMillis);
  40. }
  41. 10.sendMessageDelayed--->調(diào)用sendMessageAtTime
  42. public final boolean sendMessageDelayed(Message msg, long delayMillis){
  43. if (delayMillis < 0) {
  44. delayMillis = 0;
  45. }
  46. return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
  47. }
  48. 11.sendMessageAtTime--->調(diào)用enqueueMessage
  49. public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
  50. MessageQueue queue = mQueue;
  51. if (queue == null) {
  52. RuntimeException e = new RuntimeException(
  53. this + " sendMessageAtTime() called with no mQueue");
  54. Log.w("Looper", e.getMessage(), e);
  55. return false;
  56. }
  57. return enqueueMessage(queue, msg, uptimeMillis);
  58. }
  59. 12.sendMessageAtFrontOfQueue--->調(diào)用enqueueMessage
  60. //FIXME 該方法通過設(shè)置消息的觸發(fā)時間為0,,從而使Message加入到消息隊列的隊頭
  61. public final boolean sendMessageAtFrontOfQueue(Message msg) {
  62. MessageQueue queue = mQueue;
  63. if (queue == null) {
  64. RuntimeException e = new RuntimeException(
  65. this + " sendMessageAtTime() called with no mQueue");
  66. Log.w("Looper", e.getMessage(), e);
  67. return false;
  68. }
  69. return enqueueMessage(queue, msg, 0);
  70. }
  71. 13.enqueueMessage調(diào)用MessageQueue中的enqueueMessage
  72. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
  73. msg.target = this;
  74. if (mAsynchronous) {
  75. msg.setAsynchronous(true);
  76. }
  77. //uptimeMillis為系統(tǒng)當前的運行時間
  78. return queue.enqueueMessage(msg, uptimeMillis);
  79. }
  1. if (mAsynchronous) {
  2. msg.setAsynchronous(true);
  3. }

可以看到enqueueMessage方法時,每次都判斷是否是異步消息,。這就和MessageQueue中的Next()判斷聯(lián)系到了一起。

 

c)消息的移除--都會調(diào)用消息隊列中的移除方法

  1. public final void removeCallbacks(Runnable r){
  2. mQueue.removeMessages(this, r, null);
  3. }
  4. public final void removeCallbacks(Runnable r, Object token){
  5. mQueue.removeMessages(this, r, token);
  6. }
  7. public final void removeMessages(int what) {
  8. mQueue.removeMessages(this, what, null);
  9. }
  10. public final void removeMessages(int what, Object object) {
  11. mQueue.removeMessages(this, what, object);
  12. }
  13. public final void removeCallbacksAndMessages(Object token) {
  14. mQueue.removeCallbacksAndMessages(this, token);
  15. }

d)handleMessage(處理消息)和 dispatchMessage(分發(fā)消息)

  1. //處理消息
  2. public void handleMessage(Message msg) {
  3. }
  4. //分發(fā)消息
  5. public void dispatchMessage(Message msg) {
  6. if (msg.callback != null) {
  7. //當Message存在回調(diào)方法,,回調(diào)方法msg.callback.run()
  8. handleCallback(msg);
  9. } else {
  10. //當Handler存在Callback成員變量時,,回調(diào)方法mCallback.handleMessage();
  11. if (mCallback != null) {
  12. if (mCallback.handleMessage(msg)) {
  13. return;
  14. }
  15. }
  16. //Handler子類通過覆寫該方法來完成具體的邏輯
  17. handleMessage(msg);
  18. }
  19. }

優(yōu)先級:

Message的回調(diào)方法>Handler的回調(diào)方法>Handler的默認方法

6.總結(jié)

  1. Handler通過sendMessage()方法發(fā)送Message到MessageQueue隊列
  2. 當前Thread中Looper通過調(diào)用loop(),,不斷取出達到觸發(fā)條件的Message,,通過對應target(Handler)的dispatchMessage()方法,將Message交給Handler的handleMessage()方法來處理。
  3. 一個線程對應一個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

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

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

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導購買等信息,,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多