• Handler 原理


    线程的应用场景

    Android是单线程模型,Activity、Service、Broadcast等组件的创建,都是在主线程完成的,即UI线程。但如果需要执行一些耗时的操作时,比如:I/O的读写、大文件的读写、数据库操作以及网络上传和下载等操作都需要很长的时间,如果主线程中有较多的耗时任务,就会降低界面的响应速度,甚至失去响应,如果失去响应超过 5秒,系统就会提示强行关闭程序。解决办法就是,使用子线程Thread。

    线程与进程的区别

    线程是进程内的一个执行单元,也是进程内的可调度实体。
    两者的区别:
    1.地址空间:每个进程都至少存在一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间。
    2.线程是CPU处理器调度的基本单位,但进程不是。
    3.进程是资源分配,并且拥有单位的,同一个进程内的线程可以共享进程里的资源。

    线程间通信

    Handler机制,是Runnable 和 Activity交互的桥梁。在run中发送Message,在Handler里通过不同的Message,执行不同的任务。 

    涉及的类:

    Handler:负责消息的发送和处理,通过它可以实现子线程 和 主线程之间的通信。
    Looper:  负责管理已接收的线程消息和消息队列。
    Message: 消息载体。
    MessageQueue:消息队列,遵循先进先出的原则,它用来保存待处理的线程消息。

    线程安全问题

    当使用多个子线程来同时访问一个数据时,会出现线程安全的问题,比如:多个线程同时操作同一个数据,会导致数据不一致的问题。所以我们一般通过同步机制来解决这样的问题:synchronized(){ }同步代码块 和synchronized 同步方法。

    子线程中更新UI的几种方式

    handle.handleMessage(Message msg);
    handle.post(Runnable r);
    runOnUiThread(Runnable r);
    View.post(Runnable r);
    子线程更新UI的详细解释看这里: 面试官:子线程 真的不能更新UI ?

    Handler机制

    1. Handler定义

    Handler是一套Android消息传递机制。

    2. Handler的作用

    在多线程应用场景中,将子线程中需要更新UI的操作消息,传递到UI主线程,从而实现子线程通知UI更新最终实现异步消息处理。
        

    3 .相关概念

    Message: 消息载体,里面存储这线程消息。
    Handler. : 负责消息的发送和处理,子线程中使用sendMessage() 发送消息;在handleMessage()中处理。
    MessageQueue:消息队列,遵循先进先出的原则,存储着sendMessage()发送来的子线程消息。
    Looper: 消息循环器,负责从MessageQueue中循环取消息,再将取出的消息分发给 handleMessage(),来处理消息。每个线程只能有一个Looper (它是通过ThreadLocal实现的唯一性) ,即多个子线程可以借助同一个Handler进行通信。

    4. Handler工作机制

    1. Handler机制的工作流程:
    • Handler初始化: 在主线程中创建Looper、MessageQueue、Handler,创建完成后,Looper则自动进入消息循环状态 。同时,Handler自动绑定Looper和MessageQueue。如果消息队列为空,则线程阻塞。主线程中由于在ActivityThread的main()方法中已经初始化过了,所以就不需要在初始化Looper和MessageQueue了。
    • 子线程发送消息子线程中通过Handler向消息队列MessageQueue中发送消息。
    • 消息循环:           Looper 循环取出MessageQueue中的Message消息。Looper 将循环取出的消息分发给Handler中的handleMessage()方法。
    • 接收处理消息:    在handleMessage(Message msg)方法中处理消息。
    2. Looper的作用
    • 创建Looper对象
    • 创建MessageQueue对象
    • 让Looper对象持有当前线程
        Looper相关方法:
    • Looper.prepare()———为当前线程创建一个Looper;
    • Looper.loop() ——— 开启消息循环;
    • Looper.prepareMainLooper() ——— 为主线程创建Looper时使用,在ActivityThread有用到。
    • Looper.getMainLooper() ——— 通过该方法可以获取主线程的Looper。
    • Looper.quit() ——— 退出Looper循环。
    • Looper.quitSafely() ——— 自己创建的Looper,在不使用的时候,需要退出。
    3. Thread、Handler、Looper的对应关系
    • 一个Thread线程只能绑定到一个Looper循环器上,但可以有多个Handler实例处理者。
    • 一个Looper循环器可以绑定多个Handler实例。比如主线程的main()方法中创建了Looper和Handler对象,但是我们开发过程中仍然可以创建其他Handler对象
    • 一个Handler对象处理者,只能绑定到一个Looper循环器中。

    5. Handler的使用

    Handler的使用有两种方式:handler.sendMessage (Message msg)、handler.post (Runnable r)。
    5.1 子线程向主线程发送消息
    1. public class MainActivity extends Activity {
    2.     private static final String TAG = "MainActivity";
    3.     private Handler mHandler;
    4.     private Button btnSendeToMainThread;
    5.     private static final int MSG_SUB_TO_MAIN= 100;
    6.     @Override
    7.     protected void onCreate(Bundle savedInstanceState) {
    8.         super.onCreate(savedInstanceState);
    9.         setContentView(R.layout.activity_main);
    10.         btnSendeToMainThread = (Button) findViewById(R.id.btn_sendto_mainthread);
    11.         
    12. // 1.创建Handler,并重写handleMessage方法
    13.         mHandler = new Handler() {
    14.             @Override
    15.             public void handleMessage(Message msg) {
    16.                 super.handleMessage(msg);
    17.                 // 处理消息
    18.                 switch (msg.what) {
    19.                     case MSG_SUB_TO_MAIN:
    20.                         // 打印出处理消息的线程名和Message.obj
    21.                         Log.e(TAG, "接收到消息: " + Thread.currentThread().getName() + ","+ msg.obj);
    22.                         break;
    23.                     default:
    24.                         break;
    25.                 }
    26.             }
    27.         };
    28. btnSendeToMainThread.setOnClickListener(new View.OnClickListener() {
    29.             @Override
    30.             public void onClick(View v) {
    31.                 // 创建一个子线程,在子线程中发送消息
    32.                 new Thread(new Runnable() {
    33.                     @Override
    34.                     public void run() {
    35.                         Message msg = Message.obtain();
    36.                         msg.what = MSG_SUB_TO_MAIN;
    37.                         msg.obj = "这是一个来自子线程的消息";
    38.                         // 2.发送消息
    39.                         mHandler.sendMessage(msg);
    40.                     }
    41.                 }).start();
    42.             }
    43.         });
    44.     }
    45. }
    5.2 主线程向子线程发送消息
    1. // 创建一个子线程,并在子线程中创建一个Handler,且重写handleMessage
    2. new Thread(new Runnable() {
    3.     @Override
    4.     public void run() {
    5.         //子线程中创建Handler接收器,就必须创建Looper。
    6.         Looper.prepare();
    7.         subHandler = new Handler() {
    8.              @Override
    9.              public void handleMessage(Message msg) {
    10.                   super.handleMessage(msg);
    11.                   // 处理消息
    12.                   switch (msg.what) {
    13.                       case MSG_MAIN_TO_SUB:
    14.                            Log.e(TAG, "接收到消息:" + Thread.currentThread().getName() + ","+ msg.obj);
    15.                            break;
    16.                       default:
    17.                            break;
    18.                   }
    19.               }
    20.          };
    21.          Looper.loop();
    22.     }
    23. }).start();
    24. btnSendToSubThread = (Button) findViewById(R.id.btn_sendto_subthread);
    25. btnSendToSubThread.setOnClickListener(new View.OnClickListener() {
    26.      @Override
    27.      public void onClick(View v) {
    28.           Message msg = Message.obtain();
    29.           msg.what = MSG_MAIN_TO_SUB;
    30.           msg.obj = "这是一个来自主线程的消息";
    31.           // 主线程中发送消息
    32.           subHandler.sendMessage(msg);
    33.      }
    34. });

    6. Handler导致内存泄漏分析

    下面的两种写法会导致内存泄漏。
    1. /**
    2.  * 方式1:新建Handler子类(普通内部类)
    3.  */  
    4. public class MainActivity extends AppCompatActivity {
    5.     public static final String TAG = "carson:";
    6.     private Handler showhandler;
    7.     // 主线程创建时便自动创建Looper & 对应的MessageQueue
    8.     // 之后执行Loop()进入消息循环
    9.     @Override
    10.     protected void onCreate(Bundle savedInstanceState) {
    11.          super.onCreate(savedInstanceState);
    12.          setContentView(R.layout.activity_main);
    13. //1. 实例化自定义的Handler类对象->>分析1
    14.          //注:此处并无指定Looper,故自动绑定当前线程(主线程)的 Looper、MessageQueue
    15.          showhandler = new FHandler();
    16. // 2. 启动子线程1
    17.          new Thread() {
    18.              @Override
    19.              public void run() {
    20.                   try {
    21.                        Thread.sleep(1000);
    22.                   } catch (InterruptedException e) {
    23.                        e.printStackTrace();
    24.                   }
    25.                   // a. 定义要发送的消息
    26.                   Message msg = Message.obtain();
    27.                   msg.what = 1;// 消息标识
    28.                   msg.obj = "AA";// 消息存放
    29.                   // b. 传入主线程的Handler & 向其MessageQueue发送消息
    30.                   showhandler.sendMessage(msg);
    31.              }
    32.           }.start();
    33.   // 3. 启动子线程2
    34.           new Thread() {
    35.               @Override
    36.               public void run() {
    37.                   try {
    38.                        Thread.sleep(5000);
    39.                   } catch (InterruptedException e) {
    40.                        e.printStackTrace();
    41.                   }
    42.                   // a. 定义要发送的消息
    43.                   Message msg = Message.obtain();
    44.                   msg.what = 2;// 消息标识
    45.                   msg.obj = "BB";// 消息存放
    46.                   // b. 传入主线程的Handler & 向其MessageQueue发送消息
    47.                   showhandler.sendMessage(msg);
    48.               }
    49.            }.start();
    50.     }
    51.     // 分析1:自定义Handler子类
    52.     class FHandler extends Handler {
    53. // 通过复写handlerMessage() 从而确定更新UI的操作
    54.         @Override
    55.         public void handleMessage(Message msg) {
    56.               switch (msg.what) {
    57.                   case 1:
    58.                         Log.d(TAG, "收到线程1的消息");
    59.                      break;
    60.                   case 2:
    61.                         Log.d(TAG, " 收到线程2的消息");
    62.                      break;
    63.               }
    64.         }
    65.     }
    66. }
    1. /**
    2.  * 方式2:匿名Handler内部类
    3.  */
    4. public class MainActivity extends AppCompatActivity {
    5.    public static final String TAG = "carson:";
    6.    private Handler showhandler;
    7.    @Override
    8.    protected void onCreate(Bundle savedInstanceState) {
    9.        super.onCreate(savedInstanceState);
    10.        setContentView(R.layout.activity_main);
    11.        //1. 通过匿名内部类实例化的Handler类对象
    12.        showhandler = new  Handler(){
    13.            @Override
    14.            public void handleMessage(Message msg) {
    15.                 switch (msg.what) {
    16.                     case 1:
    17.                         Log.d(TAG, "收到线程1的消息");
    18.                         break;
    19.                     case 2:
    20.                         Log.d(TAG, " 收到线程2的消息");
    21.                         break;
    22.                 }
    23.             }
    24.        };
    25.        // 2. 启动子线程1
    26.        new Thread() {
    27.            @Override
    28.            public void run() {
    29.                try {
    30.                    Thread.sleep(1000);
    31.                } catch (InterruptedException e) {
    32.                    e.printStackTrace();
    33.                }
    34.                // a. 定义要发送的消息
    35.                Message msg = Message.obtain();
    36.                msg.what = 1;// 消息标识
    37.                msg.obj = "AA";// 消息存放
    38.                // b. 传入主线程的Handler & 向其MessageQueue发送消息
    39.                showhandler.sendMessage(msg);
    40.            }
    41.         }.start();
    42.         // 3. 启动子线程2
    43.         new Thread() {
    44.             @Override
    45.             public void run() {
    46.                 try {
    47.                     Thread.sleep(5000);
    48.                 } catch (InterruptedException e) {
    49.                     e.printStackTrace();
    50.                 }
    51.                 // a. 定义要发送的消息
    52.                 Message msg = Message.obtain();
    53.                 msg.what = 2;// 消息标识
    54.                 msg.obj = "BB";// 消息存放
    55.                 // b. 传入主线程的Handler & 向其MessageQueue发送消息
    56.                 showhandler.sendMessage(msg);
    57.             }
    58.         }.start();
    59.     }
    60. }
          
    1. 储备知识
    在Java中,非静态内部类匿名内部类 都是会默认持有外部类的引用的。
    主线程中的Looper对象的生命周期 = 该应用程序的生命周期
    2. 内存泄漏原因描述
    当Handler消息队列MessageQueue中,还有未处理的消息或者正在处理的消息时,消息队列中的Message会持有Handler实例的引用,而Handler实例又持有着外部类MainActivity的引用。此时如果外部类MainActivity被销毁,但由于上述的引用关系,垃圾回收器(GC)无法回收MainActivity,从而造成内存泄漏。
    最终原因,是由于Looper的生命周期 > MainActivity的生命周期。
    3. 内存泄漏的解决方案
         解决方案一:
         静态内部类 + 弱引用
         原理:静态内部类,默认不会持有外部类的引用。从而使得逐层的引用关系不复存在;
         弱引用对象拥有的生命周期很短暂。垃圾回收器执行扫描时,一旦发现了具有弱引用的对象,
         不管内存空间是否充足,都会回收这个弱引用对象的内存。
         解决方案二:
         外部类被销毁时,清空MessageQueue消息队列。
         这样不仅使得逐层的引用关系不复存在,同时使得Looper的生命周期与外部类实现了同步。
         清除消息队列的方法是:removeCallbackAndMessages(null);

    7. Handler中的Looper如何停止

    可以通过调用 handler.getLooper().quit(),执行完退出之后,Looper.loop() 后面的代码才会执行。否则后面的代码是永远都不会执行的。
    1. public class LooperActivity extends AppCompatActivity {
    2.     private static final String TAG = "LooperActivity";
    3.     private Button btn;
    4.     private Handler mHandler;
    5.     @Override
    6.     protected void onCreate(Bundle savedInstanceState) {
    7.         super.onCreate(savedInstanceState);
    8.         setContentView(R.layout.activity_looper);
    9.         btn = (Button) findViewById(R.id.btn);
    10.         // 开启一个子线程,去执行异步任务
    11.         new Thread(new Runnable() {
    12.             @Override
    13.             public void run() {
    14.                 Looper.prepare();
    15.                 mHandler = new Handler() {
    16.                     @Override
    17.                     public void handleMessage(Message msg) {
    18.                         super.handleMessage(msg);
    19.                     }
    20.                 };
    21.                 Log.e(TAG, "Looper.loop之前" );
    22.                 // Looper.loop方法是一个死循环
    23.                 Looper.loop();
    24.                 // 得不到执行
    25.                 Log.e(TAG, "Looper.loop之后" );
    26.             }
    27.         }).start();
    28.         btn.setOnClickListener(new View.OnClickListener() {
    29.             @Override
    30.             public void onClick(View v) {
    31.                 // 调用Looper的quit方法,停止Looper
    32.                 mHandler.getLooper().quit();
    33.             }
    34.         });
    35.     }
    36. }

    8. Looper 死循环为什么不会导致应用卡死?

    Launch桌面的图标第一次启动 Activity 时,会最终走到 ActivityThread 的 main 方法,在 main 方法里面创建了 Looper 和 MessageQueue 来处理主线程的消息,然后 Looper.loop 方法就进入死循环。我们的 Activity 的生命周期都是通过 Handler 机制来处理的。在看看看 loop 方法循环:

    主线程主要依靠的就是消息循环,一旦退出消息循环,那么应用也就退出了。 Looper.loop() 方法可能会引起主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理消息事件,就不会产生 ANR 异常。

    造成 ANR 异常的不是主线程阻塞,而是主线程中 Looper 的消息处理过程发生了任务阻塞从而无法响应手势操作,不能及时刷新UI。

    阻塞与ANR无必然关系,虽然主线程在没有消息可处理的时候是阻塞状态的,但是只要保证有消息的时候能够得到立即处理,程序就不会发生 ANR。

    总结:应用卡死跟这个Looper 没有关系,应用在没有消息需要处理的时候,Looper 它是在睡眠,释放线程;卡死是 ANR,而 Looper 是睡眠。

    9. MessageQueue源码详解

    1. 源码-----插入消息
    1. boolean enqueueMessage(Message msg, long when) {
    2.     //即不允许添加同步消息屏障,实现异步消息了。
    3.     if (msg.target == null) {
    4.         throw new IllegalArgumentException("Message must have a target.");
    5.     }
    6.     if (msg.isInUse()) {
    7.         throw new IllegalStateException(msg + " This message is already in use.");
    8.     }
    9.     synchronized (this) {
    10.         //. . . . . .
    11.         msg.markInUse();
    12.         msg.when = when;
    13.         Message p = mMessages;
    14.         boolean needWake;
    15.         //当队列为空,第一次发来的 message,或者新发来的 message 的时间更小的情况,就走if块,添加到链表头部。
    16.         if (p == null || when == 0 || when < p.when) {
    17.             // New head, wake up the event queue if blocked.
    18.             msg.next = p;
    19.             mMessages = msg;
    20.             //如果此时Looper处于阻塞状态,则唤醒。并循环执行 message 的读取。
    21.             needWake = mBlocked;
    22.         } else {
    23.             // Inserted within the middle of the queue.  Usually we don't have to wake
    24.             // up the event queue unless there is a barrier at the head of the queue
    25.             // and the message is the earliest asynchronous message in the queue.
    26.             // 将发来的 message 插入到 queue 队列的中间或者尾部。
    27.             // 这种情况下,我们不需要唤醒事件队列。除非有一个消息屏障在队列的头部,并且它是队列中最早的异步消息。
    28.             
    29.             // 判断当前发送来的 message 是否是一个异步消息,如果是异步消息,并且队列 queue头部含有 消息屏障
    30.             // p.target = null, 同时当前 queue是处于阻塞状态。则设为 “需要唤醒队列”。 
    31.             //这里的 p 消息,也有可能是 postAsyncBarrier()中传到 消息队列里的,因此此处需要处理异步消息的情况
    32.             needWake = mBlocked && p.target == null && msg.isAsynchronous();
    33.             Message prev;
    34.             // 执行一个 for循环,并通过时间的对比,将新发来的消息,插入到队列中适当的位置。
    35.             for (;;) {
    36.                 prev = p;
    37.                 p = p.next;
    38.                 if (p == null || when < p.when) {
    39.                     break;
    40.                 }
    41.                 //如果队列头部有了 target=null 的一个消息屏障,并且当前发送过来的 message 是一个异步消息。
    42.                 // 如果添加 message 之前,队列中还有其他异步消息等待处理,则就不唤醒 queue。否则就唤醒。
    43.                 if (needWake && p.isAsynchronous()) {
    44.                     needWake = false;
    45.                 }
    46.             }
    47.             msg.next = p;
    48.             prev.next = msg;
    49.         }
    50.         // We can assume mPtr != 0 because mQuitting is false.
    51.         if (needWake) {
    52.             nativeWake(mPtr);
    53.         }
    54.     }
    55.     return true;
    56. }

    2. 源码——Looper

    1. public static void loop() {
    2.     boolean slowDeliveryDetected = false;
    3.     for (;;) {
    4.         Message msg = queue.next(); // might block
    5.         if (msg == null) {
    6.             // No message indicates that the message queue is quitting.
    7.             return;
    8.         }
    9.         try {
    10.             // 将事件交由 Handler处理
    11.             msg.target.dispatchMessage(msg);
    12.             dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
    13.         } finally {
    14.             if (traceTag != 0) {
    15.                 Trace.traceEnd(traceTag);
    16.             }
    17.         }
    18.         // 回收msg,以便 Message.obtain() 实现复用。
    19.         msg.recycleUnchecked();
    20.     }
    21. }

    3. 源码——MessageQueue

    1. Message next() {
    2.     // mPtr,Native层的 MessageQueue。
    3.     final long ptr = mPtr;
    4.     if (ptr == 0) {
    5.         return null;
    6.     }
    7.     int nextPollTimeoutMillis = 0;
    8.     for (;;) {
    9.         // Native层设置阻塞时间—延迟消息的时间
    10.         nativePollOnce(ptr, nextPollTimeoutMillis);
    11.         synchronized (this) {
    12.             // Try to retrieve the next message.  Return if found.
    13.             final long now = SystemClock.uptimeMillis();
    14.             Message prevMsg = null;
    15.             Message msg = mMessages; // 获取链表头部信息
    16.             if (msg != null && msg.target == null) {
    17.                 // Stalled by a barrier.  Find the next asynchronous message in the queue.
    18.                 // 循环遍历,查找第一个 异步消息。会直接忽略 queue 中的其他消息。
    19.                 do {
    20.                     prevMsg = msg;
    21.                     msg = msg.next;
    22.                 } while (msg != null && !msg.isAsynchronous());
    23.             }
    24.             if (msg != null) {
    25.                 if (now < msg.when) {
    26.                     // Next message is not ready.  Set a timeout to wake up when it is ready.
    27.                     // 根据延迟消息,设置阻塞时间
    28.                     nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
    29.                 } else {
    30.                     // 返回一个即时消息,或者返回一个已到时间的 延迟消息。
    31.                     mBlocked = false// 设置为 queue未阻塞状态
    32.                     if (prevMsg != null) {
    33.                         prevMsg.next = msg.next;
    34.                     } else {
    35.                         mMessages = msg.next;
    36.                     }
    37.                     msg.next = null;
    38.                     msg.markInUse();
    39.                     return msg;
    40.                 }
    41.             } else {
    42.                 // queue 队列中没有消息时,会返回 -1,表示 nativePollOnce() 会一直阻塞 
    43.                 nextPollTimeoutMillis = -1;
    44.             }
    45.         }
    46.     }
    47. }

    4. 延迟消息Handler.postDelay(new Runnable(), 2000)

    1. //使用方式
    2. Handler handler = new Handler();
    3. handler.postDelayed(new Runnable() {
    4.     @Override
    5.     public void run() {
    6.        //延迟一秒后,执行这里面的内容
    7.     }
    8. },1000);
    9. handler.removeCallback();

    传入的Runnable,最终存储在了mesage.callback 中。也是一种延迟消息,当到时间时,looper循环取出后,会执行Handler中的dispatchMessage()方法。判断如果 callback 不为空,就执行 callback.run()。callback就是一个Rnnable对象。

    Hanlder同步消息屏障

    1. @Override
    2. protected void onCreate(Bundle savedInstanceState) {
    3.     super.onCreate(savedInstanceState);
    4.     setContentView(R.layout.activity_main);
    5.     final Handler handler = new Handler() {
    6.         @Override
    7.         public void handleMessage(Message msg) {
    8.             super.handleMessage(msg);
    9.             System.out.println("打印: " + msg.what);
    10.             switch (msg.what){
    11.                 case 999:
    12.                     //第四步 异步消息执行完之后必需,移除消息屏障,否则会一直阻塞 queue。
    13.                     removeSyncBarrier();
    14.                     break;
    15.             }
    16.         }
    17.     };
    18.     new Thread(new Runnable() {
    19.         int max = 0;
    20.         @Override
    21.         public void run() {
    22.             while (max != 10) {
    23.                 handler.sendEmptyMessageDelayed(max, 5000 + 500 * max);
    24.                 max++;
    25.             }
    26.         }
    27.     }).start();
    28.     new Thread(new Runnable() {
    29.         @Override
    30.         public void run() {
    31.             Message message = Message.obtain();
    32.             message.what = 999;
    33.             // 第一步 设置 message为 异步消息
    34.             message.setAsynchronous(true);
    35.             // 第二步 设置消息屏障
    36.             postSyncBarrier();
    37.             // 第三步 发送消息
    38.             handler.sendMessageDelayed(message, 0);
    39.         }
    40.     }).start();
    41. }
    42. private int token = 0;//设置消息屏障时返回的token,用于删除消息屏障时使用。
    43. // 反射执行投递同步屏障
    44. public void postSyncBarrier() {
    45.     Method method = null;
    46.     try {
    47.         method = MessageQueue.class.getDeclaredMethod("postSyncBarrier");
    48.         token = (int) method.invoke(Looper.getMainLooper().getQueue());
    49.     } catch (NoSuchMethodException e) {
    50.         e.printStackTrace();
    51.     } catch (IllegalAccessException e) {
    52.         e.printStackTrace();
    53.     } catch (InvocationTargetException e) {
    54.         e.printStackTrace();
    55.     }
    56. }
    57. // 反射执行移除同步屏障
    58. public void removeSyncBarrier() {
    59.     Method method = null;
    60.     try {
    61.         method = MessageQueue.class.getDeclaredMethod("removeSyncBarrier", int.class);
    62.         method.invoke(Looper.getMainLooper().getQueue(), token);
    63.     } catch (NoSuchMethodException e) {
    64.         e.printStackTrace();
    65.     } catch (IllegalAccessException e) {
    66.         e.printStackTrace();
    67.     } catch (InvocationTargetException e) {
    68.         e.printStackTrace();
    69.     }
    70. }

    源码分析 --- 消息屏障

    步骤一、Message设置为异步消息
    步骤二 、在 queue中设置消息屏障
    1. // 8.0之后该方法改为 @hide隐藏了,因此需要通过反射获取。
    2. public int postSyncBarrier() {
    3.     return postSyncBarrier(SystemClock.uptimeMillis());
    4. }
    5. //注意⚠️ 这里添加message的时候,target没有设置,默认为null — — 即消息屏障
    6. private int postSyncBarrier(long when) {
    7.     // Enqueue a new sync barrier token.
    8.     // We don't need to wake the queue because the purpose of a barrier is to stall it.
    9.     synchronized (this) {
    10.         final int token = mNextBarrierToken++;
    11.         final Message msg = Message.obtain();
    12.         msg.markInUse();
    13.         msg.when = when;
    14.         msg.arg1 = token;
    15.         Message prev = null;
    16.         Message p = mMessages;
    17.         // 从链表的头部开始,找出队列中最后一个message,或者找出queue 中间的延迟时间晚于当前message延迟时间的
    18.         if (when != 0) {
    19.             while (p != null && p.when <= when) {
    20.                 prev = p;
    21.                 p = p.next;
    22.             }
    23.         }
    24.         if (prev != null) { // 如果queue队列前面有其他message,则将当前 message插入到这两个 message中间 
    25.             msg.next = p;
    26.             prev.next = msg;
    27.         } else// 如果前面没有 message,则将当前的 message设置为最头部的 message。
    28.             msg.next = p;
    29.             mMessages = msg;
    30.         }
    31.         // 返回一个 token,用于接下来的 移除工作。
    32.         return token;
    33.     }
    34. }

    步骤三、发送消息

    步骤四、移除消息屏障
    1. public void removeSyncBarrier(int token) {
    2.     // Remove a sync barrier token from the queue.
    3.     // If the queue is no longer stalled by a barrier then wake it.
    4.     synchronized (this) {
    5.         Message prev = null;
    6.         Message p = mMessages;
    7.         while (p != null && (p.target != null || p.arg1 != token)) {
    8.             prev = p;
    9.             p = p.next;
    10.         }
    11.         if (p == null) {
    12.             throw new IllegalStateException("The specified message queue synchronization "
    13.                     + " barrier token has not been posted or has already been removed.");
    14.         }
    15.         final boolean needWake;
    16.         if (prev != null) {
    17.             prev.next = p.next;
    18.             needWake = false;
    19.         } else {
    20.             mMessages = p.next;
    21.             needWake = mMessages == null || mMessages.target != null;
    22.         }
    23.         p.recycleUnchecked();
    24.         // If the loop is quitting then it is already awake.
    25.         // We can assume mPtr != 0 when mQuitting is false.
    26.         if (needWake && !mQuitting) {
    27.             nativeWake(mPtr);
    28.         }
    29.     }
    30. }

     

  • 相关阅读:
    动态规划-矩阵连乘
    CS5340国产替代DP5340多比特音频 A/D 转换器
    机器学习笔记之高斯过程(二)高斯过程回归——权重空间角度
    设计模式-Strategy模式(策略模式)
    【Android笔记53】Android之实现应用程序中的画中画效果
    GaussDB技术解读——GaussDB架构介绍(五)
    成都无人机测绘公司 无人机测绘服务 无人机航测作业
    Dreamweaver 2021 for Mac 激活版:网页设计工具
    【每日OJ题—— 142. 环形链表 II (链表)】
    Java打包jar包的全部方式
  • 原文地址:https://blog.csdn.net/m0_49508485/article/details/127998204