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);
}
}
}