- public class MainActivity extends Activity {
- private static final String TAG = "MainActivity";
-
- private Handler mHandler;
- private Button btnSendeToMainThread;
- private static final int MSG_SUB_TO_MAIN= 100;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- btnSendeToMainThread = (Button) findViewById(R.id.btn_sendto_mainthread);
-
- // 1.创建Handler,并重写handleMessage方法
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- // 处理消息
- switch (msg.what) {
- case MSG_SUB_TO_MAIN:
- // 打印出处理消息的线程名和Message.obj
- Log.e(TAG, "接收到消息: " + Thread.currentThread().getName() + ","+ msg.obj);
- break;
- default:
- break;
- }
- }
- };
- btnSendeToMainThread.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // 创建一个子线程,在子线程中发送消息
- new Thread(new Runnable() {
- @Override
- public void run() {
- Message msg = Message.obtain();
- msg.what = MSG_SUB_TO_MAIN;
- msg.obj = "这是一个来自子线程的消息";
- // 2.发送消息
- mHandler.sendMessage(msg);
- }
- }).start();
- }
- });
- }
- }
- // 创建一个子线程,并在子线程中创建一个Handler,且重写handleMessage
- new Thread(new Runnable() {
- @Override
- public void run() {
- //子线程中创建Handler接收器,就必须创建Looper。
- Looper.prepare();
- subHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- // 处理消息
- switch (msg.what) {
- case MSG_MAIN_TO_SUB:
- Log.e(TAG, "接收到消息:" + Thread.currentThread().getName() + ","+ msg.obj);
- break;
- default:
- break;
- }
- }
- };
- Looper.loop();
- }
- }).start();
-
- btnSendToSubThread = (Button) findViewById(R.id.btn_sendto_subthread);
- btnSendToSubThread.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Message msg = Message.obtain();
- msg.what = MSG_MAIN_TO_SUB;
- msg.obj = "这是一个来自主线程的消息";
- // 主线程中发送消息
- subHandler.sendMessage(msg);
- }
- });
- /**
- * 方式1:新建Handler子类(普通内部类)
- */
- public class MainActivity extends AppCompatActivity {
- public static final String TAG = "carson:";
- private Handler showhandler;
- // 主线程创建时便自动创建Looper & 对应的MessageQueue
- // 之后执行Loop()进入消息循环
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //1. 实例化自定义的Handler类对象->>分析1
- //注:此处并无指定Looper,故自动绑定当前线程(主线程)的 Looper、MessageQueue
- showhandler = new FHandler();
- // 2. 启动子线程1
- new Thread() {
- @Override
- public void run() {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // a. 定义要发送的消息
- Message msg = Message.obtain();
- msg.what = 1;// 消息标识
- msg.obj = "AA";// 消息存放
- // b. 传入主线程的Handler & 向其MessageQueue发送消息
- showhandler.sendMessage(msg);
- }
- }.start();
-
- // 3. 启动子线程2
- new Thread() {
- @Override
- public void run() {
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // a. 定义要发送的消息
- Message msg = Message.obtain();
- msg.what = 2;// 消息标识
- msg.obj = "BB";// 消息存放
- // b. 传入主线程的Handler & 向其MessageQueue发送消息
- showhandler.sendMessage(msg);
- }
- }.start();
- }
-
- // 分析1:自定义Handler子类
- class FHandler extends Handler {
- // 通过复写handlerMessage() 从而确定更新UI的操作
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case 1:
- Log.d(TAG, "收到线程1的消息");
- break;
- case 2:
- Log.d(TAG, " 收到线程2的消息");
- break;
- }
- }
- }
- }
- /**
- * 方式2:匿名Handler内部类
- */
- public class MainActivity extends AppCompatActivity {
- public static final String TAG = "carson:";
- private Handler showhandler;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- //1. 通过匿名内部类实例化的Handler类对象
- showhandler = new Handler(){
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case 1:
- Log.d(TAG, "收到线程1的消息");
- break;
- case 2:
- Log.d(TAG, " 收到线程2的消息");
- break;
- }
- }
- };
-
- // 2. 启动子线程1
- new Thread() {
- @Override
- public void run() {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // a. 定义要发送的消息
- Message msg = Message.obtain();
- msg.what = 1;// 消息标识
- msg.obj = "AA";// 消息存放
- // b. 传入主线程的Handler & 向其MessageQueue发送消息
- showhandler.sendMessage(msg);
- }
- }.start();
-
- // 3. 启动子线程2
- new Thread() {
- @Override
- public void run() {
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- // a. 定义要发送的消息
- Message msg = Message.obtain();
- msg.what = 2;// 消息标识
- msg.obj = "BB";// 消息存放
- // b. 传入主线程的Handler & 向其MessageQueue发送消息
- showhandler.sendMessage(msg);
- }
- }.start();
- }
- }
- public class LooperActivity extends AppCompatActivity {
- private static final String TAG = "LooperActivity";
- private Button btn;
- private Handler mHandler;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_looper);
- btn = (Button) findViewById(R.id.btn);
- // 开启一个子线程,去执行异步任务
- new Thread(new Runnable() {
- @Override
- public void run() {
- Looper.prepare();
- mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- }
- };
- Log.e(TAG, "Looper.loop之前" );
- // Looper.loop方法是一个死循环
- Looper.loop();
- // 得不到执行
- Log.e(TAG, "Looper.loop之后" );
- }
- }).start();
- btn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // 调用Looper的quit方法,停止Looper
- mHandler.getLooper().quit();
- }
- });
- }
- }
Launch桌面的图标第一次启动 Activity 时,会最终走到 ActivityThread 的 main 方法,在 main 方法里面创建了 Looper 和 MessageQueue 来处理主线程的消息,然后 Looper.loop 方法就进入死循环。我们的 Activity 的生命周期都是通过 Handler 机制来处理的。在看看看 loop 方法循环:
主线程主要依靠的就是消息循环,一旦退出消息循环,那么应用也就退出了。 Looper.loop() 方法可能会引起主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理消息事件,就不会产生 ANR 异常。
造成 ANR 异常的不是主线程阻塞,而是主线程中 Looper 的消息处理过程发生了任务阻塞从而无法响应手势操作,不能及时刷新UI。
阻塞与ANR无必然关系,虽然主线程在没有消息可处理的时候是阻塞状态的,但是只要保证有消息的时候能够得到立即处理,程序就不会发生 ANR。
总结:应用卡死跟这个Looper 没有关系,应用在没有消息需要处理的时候,Looper 它是在睡眠,释放线程;卡死是 ANR,而 Looper 是睡眠。
- boolean enqueueMessage(Message msg, long when) {
- //即不允许添加同步消息屏障,实现异步消息了。
- 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) {
- //. . . . . .
- msg.markInUse();
- msg.when = when;
- Message p = mMessages;
- boolean needWake;
- //当队列为空,第一次发来的 message,或者新发来的 message 的时间更小的情况,就走if块,添加到链表头部。
- if (p == null || when == 0 || when < p.when) {
- // New head, wake up the event queue if blocked.
- msg.next = p;
- mMessages = msg;
- //如果此时Looper处于阻塞状态,则唤醒。并循环执行 message 的读取。
- needWake = mBlocked;
- } else {
- // Inserted within the middle of the queue. Usually we don't have to wake
- // up the event queue unless there is a barrier at the head of the queue
- // and the message is the earliest asynchronous message in the queue.
- // 将发来的 message 插入到 queue 队列的中间或者尾部。
- // 这种情况下,我们不需要唤醒事件队列。除非有一个消息屏障在队列的头部,并且它是队列中最早的异步消息。
-
- // 判断当前发送来的 message 是否是一个异步消息,如果是异步消息,并且队列 queue头部含有 消息屏障
- // p.target = null, 同时当前 queue是处于阻塞状态。则设为 “需要唤醒队列”。
- //这里的 p 消息,也有可能是 postAsyncBarrier()中传到 消息队列里的,因此此处需要处理异步消息的情况
- needWake = mBlocked && p.target == null && msg.isAsynchronous();
- Message prev;
- // 执行一个 for循环,并通过时间的对比,将新发来的消息,插入到队列中适当的位置。
- for (;;) {
- prev = p;
- p = p.next;
- if (p == null || when < p.when) {
- break;
- }
- //如果队列头部有了 target=null 的一个消息屏障,并且当前发送过来的 message 是一个异步消息。
- // 如果添加 message 之前,队列中还有其他异步消息等待处理,则就不唤醒 queue。否则就唤醒。
- if (needWake && p.isAsynchronous()) {
- needWake = false;
- }
- }
- msg.next = p;
- prev.next = msg;
- }
- // We can assume mPtr != 0 because mQuitting is false.
- if (needWake) {
- nativeWake(mPtr);
- }
- }
- return true;
- }
2. 源码——Looper
- public static void loop() {
- boolean slowDeliveryDetected = false;
- for (;;) {
- Message msg = queue.next(); // might block
- if (msg == null) {
- // No message indicates that the message queue is quitting.
- return;
- }
- try {
- // 将事件交由 Handler处理
- msg.target.dispatchMessage(msg);
- dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
- } finally {
- if (traceTag != 0) {
- Trace.traceEnd(traceTag);
- }
- }
- // 回收msg,以便 Message.obtain() 实现复用。
- msg.recycleUnchecked();
- }
- }
3. 源码——MessageQueue
- Message next() {
- // mPtr,Native层的 MessageQueue。
- final long ptr = mPtr;
- if (ptr == 0) {
- return null;
- }
- int nextPollTimeoutMillis = 0;
- for (;;) {
- // Native层设置阻塞时间—延迟消息的时间
- nativePollOnce(ptr, nextPollTimeoutMillis);
- synchronized (this) {
- // Try to retrieve the next message. Return if found.
- final long now = SystemClock.uptimeMillis();
- Message prevMsg = null;
- Message msg = mMessages; // 获取链表头部信息
- if (msg != null && msg.target == null) {
- // Stalled by a barrier. Find the next asynchronous message in the queue.
- // 循环遍历,查找第一个 异步消息。会直接忽略 queue 中的其他消息。
- do {
- prevMsg = msg;
- msg = msg.next;
- } while (msg != null && !msg.isAsynchronous());
- }
- if (msg != null) {
- if (now < msg.when) {
- // Next message is not ready. Set a timeout to wake up when it is ready.
- // 根据延迟消息,设置阻塞时间
- nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
- } else {
- // 返回一个即时消息,或者返回一个已到时间的 延迟消息。
- mBlocked = false; // 设置为 queue未阻塞状态
- if (prevMsg != null) {
- prevMsg.next = msg.next;
- } else {
- mMessages = msg.next;
- }
- msg.next = null;
- msg.markInUse();
- return msg;
- }
- } else {
- // queue 队列中没有消息时,会返回 -1,表示 nativePollOnce() 会一直阻塞
- nextPollTimeoutMillis = -1;
- }
- }
- }
- }
4. 延迟消息Handler.postDelay(new Runnable(), 2000)
- //使用方式
- Handler handler = new Handler();
- handler.postDelayed(new Runnable() {
- @Override
- public void run() {
- //延迟一秒后,执行这里面的内容
- }
- },1000);
- handler.removeCallback();
传入的Runnable,最终存储在了mesage.callback 中。也是一种延迟消息,当到时间时,looper循环取出后,会执行Handler中的dispatchMessage()方法。判断如果 callback 不为空,就执行 callback.run()。callback就是一个Rnnable对象。
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- final Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- System.out.println("打印: " + msg.what);
- switch (msg.what){
- case 999:
- //第四步 异步消息执行完之后必需,移除消息屏障,否则会一直阻塞 queue。
- removeSyncBarrier();
- break;
- }
- }
- };
-
- new Thread(new Runnable() {
- int max = 0;
-
- @Override
- public void run() {
- while (max != 10) {
- handler.sendEmptyMessageDelayed(max, 5000 + 500 * max);
- max++;
- }
- }
- }).start();
-
- new Thread(new Runnable() {
- @Override
- public void run() {
- Message message = Message.obtain();
- message.what = 999;
- // 第一步 设置 message为 异步消息
- message.setAsynchronous(true);
- // 第二步 设置消息屏障
- postSyncBarrier();
- // 第三步 发送消息
- handler.sendMessageDelayed(message, 0);
- }
- }).start();
- }
-
- private int token = 0;//设置消息屏障时返回的token,用于删除消息屏障时使用。
-
- // 反射执行投递同步屏障
- public void postSyncBarrier() {
- Method method = null;
- try {
- method = MessageQueue.class.getDeclaredMethod("postSyncBarrier");
- token = (int) method.invoke(Looper.getMainLooper().getQueue());
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }
-
- // 反射执行移除同步屏障
- public void removeSyncBarrier() {
- Method method = null;
- try {
- method = MessageQueue.class.getDeclaredMethod("removeSyncBarrier", int.class);
- method.invoke(Looper.getMainLooper().getQueue(), token);
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }
- // 8.0之后该方法改为 @hide隐藏了,因此需要通过反射获取。
- public int postSyncBarrier() {
- return postSyncBarrier(SystemClock.uptimeMillis());
- }
- //注意⚠️ 这里添加message的时候,target没有设置,默认为null — — 即消息屏障
- private int postSyncBarrier(long when) {
- // Enqueue a new sync barrier token.
- // We don't need to wake the queue because the purpose of a barrier is to stall it.
- synchronized (this) {
- final int token = mNextBarrierToken++;
- final Message msg = Message.obtain();
- msg.markInUse();
- msg.when = when;
- msg.arg1 = token;
- Message prev = null;
- Message p = mMessages;
- // 从链表的头部开始,找出队列中最后一个message,或者找出queue 中间的延迟时间晚于当前message延迟时间的
- if (when != 0) {
- while (p != null && p.when <= when) {
- prev = p;
- p = p.next;
- }
- }
- if (prev != null) { // 如果queue队列前面有其他message,则将当前 message插入到这两个 message中间
- msg.next = p;
- prev.next = msg;
- } else { // 如果前面没有 message,则将当前的 message设置为最头部的 message。
- msg.next = p;
- mMessages = msg;
- }
- // 返回一个 token,用于接下来的 移除工作。
- return token;
- }
- }
步骤三、发送消息
- public void removeSyncBarrier(int token) {
- // Remove a sync barrier token from the queue.
- // If the queue is no longer stalled by a barrier then wake it.
- synchronized (this) {
- Message prev = null;
- Message p = mMessages;
- while (p != null && (p.target != null || p.arg1 != token)) {
- prev = p;
- p = p.next;
- }
- if (p == null) {
- throw new IllegalStateException("The specified message queue synchronization "
- + " barrier token has not been posted or has already been removed.");
- }
- final boolean needWake;
- if (prev != null) {
- prev.next = p.next;
- needWake = false;
- } else {
- mMessages = p.next;
- needWake = mMessages == null || mMessages.target != null;
- }
- p.recycleUnchecked();
-
- // If the loop is quitting then it is already awake.
- // We can assume mPtr != 0 when mQuitting is false.
- if (needWake && !mQuitting) {
- nativeWake(mPtr);
- }
- }
- }