目录
-
消息机制简介
Android系统通过Handler、Message、MessageQueue、Looper实现消息机制。Handler负责消息的发送和处理(接收);MessageQueue是消息队列,里面保存了Handler发送的所有的消息(Message),Message是指具体的消息,它持有Handler对象(划重点:这个持有很关键)。Looper执行消息循环,底层是C++的epoll机制,只有在有消息的时候,才会唤醒线程。Looper通过while循环遍历MessageQueque,如果有消息时(MessageQueue中的Message合法),调用Message所持有的Handler对象的dispatchMessage方法分发消息,dispatchMessage最终调用Handler对象的handleMessage方法处理消息。
消息机制主要用在线程间的通信(通过Message传递数据)。接下来,我们通过一个简单的Demo,从源码的角度来捋一下消息机制。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Handler h = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
// 主线程接受消息
super.handleMessage(msg);
long id = Thread.currentThread().getId();
}
};
new Thread(new Runnable() {
@Override
public void run() {
// 子线程消息发送
long id = Thread.currentThread().getId();
Message message = new Message();
message.arg1 = 100;
message.what = 102;
h.sendMessage(message);
}
}).start();
}
}
子线程中消息循环需要开启Looper消息循环( Looper.prepare(); Looper.loop() 这两个方法),否则会异常
public class MyThread extends Thread {
public static final String TAG = "Zhang";
public Handler mHandler = null;
@Override
public void run() {
Log.d(TAG, "进入Thread的run");
// 子线程中需要调用prepare方法初始化
Looper.prepare();
mHandler = new Handler(Looper.myLooper()){
@Override
public void handleMessage(Message msg){
Log.d(TAG, "获得了message");
super.handleMessage(msg);
}
};
// 开启消息循环
Looper.loop();
}
}
-
消息发送
以下4个api都是用来发送消息,but前面三个最终还是调用第四个API,其作用都是向详细队列插入消息。
Handler.post();
Handler.postDelayed();
Handler.postAtTime();
Handler.sendMessageAtTime();
frameworks/base/core/java/android/os/Handler.java
/**
不论是使用postDelayed 或 sendMessageDelayed 或 sendMessageAtTime,最终都是调用enqueueMessage方法,向消息队列插入消息
**/
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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 enqueueMess