在Android 消息机制里面主要如下几个类Looper、MessageQueue、Message、Handler,下面简单的介绍一下他们之间的关系。
-
Looper
每一个线程只有一个Looper,每个线程在初始化Looper之后,然后Looper会维护好该线程的消息队列,用来存放Handler发送的Message,并处理消息队列出队的Message。它的特点是它跟它的线程是绑定的,处理消息也是在Looper所在的线程去处理,所以当我们在主线程创建Handler时,它就会跟主线程唯一的Looper绑定,从而我们使用Handler在子线程发消息时,最终也是在主线程处理,达到了异步的效果。 -
MessageQueue
MessageQueue是一个消息队列,用来存放Handler发送的消息。每个线程最多只有一个MessageQueue。MessageQueue通常都是由Looper来管理,而主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个MessageQueue。其他非主线程,不会自动创建Looper。 -
Message
消息对象,就是MessageQueue里面存放的对象,一个MessageQueu可以包括多个Message。当我们需要发送一个Message时,我们一般不建议使用new Message()的形式来创建,更推荐使用Message.obtain()来获取Message实例,因为在Message类里面定义了一个消息池,当消息池里存在未使用的消息时,便返回,如果没有未使用的消息,则通过new的方式创建返回,所以使用Message.obtain()的方式来获取实例可以大大减少当有大量Message对象而产生的垃圾回收问题。
1. 自定义消息实体Message.java
public class Message {
public int msg1;
public int msg2;
public int what;
public Object obj;
public Handler target;
public Runnable runnable;
}
2. 自定义消息队列-MessageQueue.java
public class MessageQueue {
private BlockingQueue<Message> queue;
private boolean quit = false;
public MessageQueue() {
queue = new LinkedBlockingQueue<>();
queue.clear();
}
//入队
public boolean enqueueMessage(Message msg) {
if (msg.target == null) {
throw new RuntimeException("消息必须有一个消息处理者");
}
try {
queue.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
//出队
public Message next() {
Message msg = null;
if (quit) {
return null;
}
try {
msg = queue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return msg;
}
//销毁
public synchronized void quit() {
quit = true;
}
}
3. 自定义消息循环器-Looper.java
public class Looper {
private static ThreadLocal<Looper> threadLocal = new ThreadLocal<>();
private static Looper mLooper;
public MessageQueue queue;
//一个线程对应一个阻塞队列
private Looper() {
queue = new MessageQueue();
}
//获取当前线程相对应的Looper对象
public static Looper myLooper() {
return threadLocal.get();
//当未调用prepare()方法时。ThreadLocal.get()方法返回的为null;
}
//为本线程准备对应的MyLooper对象
public static void prepare() {
if (threadLocal.get() != null) {
throw new RuntimeException( "Only one MyLooper may be created
per thread");
}
threadLocal.set(new Looper());
}
//这里启动消息循环
public static void loop() {
while (true) {
mLooper = Looper();
MessageQueue mQueue = mLooper.queue;
Message msg = mQueue.next();
// take()方法是个阻塞方法。线程运行到此会阻塞住。以准备接收发过来的消息
msg.target.dispatchMessage(msg);
}
}
}
4. 自定义消息处理器-Handler.java
public class Handler {
private MessageQueue queue;// 用于进行线程间通信的阻塞队列
private CallBack callBack; // 处理消息的回调
public Handler(CallBack callBack) {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new RuntimeException("在新开的线程中。创建MyHandler对象
需要先调用Looper.prepare()方法。");
}
queue = looper.queue;
this.callBack = callBack;
}
//消息接收的回调
public interface CallBack {
void handleMessage(Message msg);
}
//发送消息
public void sendMessage(Message msg) {
msg.target = this;
queue.enqueueMessage(msg);
}
//派发消息
public void dispatchMessage(Message msg) {
callBack.handleMessage(msg);
}
}
5. 测试代码TestClient.java
public class TestClient {
Handler mainHandler;
public static void main(String[] args) {
new TestClient().test();
}
private void test() {
//初始化主线程Looper
Looper.prepare();
mainHandler = new Handler(new CallBack() {
@Override
public void handleMessage(Message msg) {
// 刷新界面
String obj = (String) msg.obj;
LogUtil.print("刷新界面:" + obj);
}
});
//发起网络请求
LogUtil.print("在主线程发起一个网络请求");
NetThread netThread = new NetThread("http://baidu.com");
netThread.start();
LogUtil.print("在主线程继续其它操作");
//开始消息循环
Looper.loop();
}
//网络线程类
private class NetThread extends Thread {
private String url;
public NetThread(String url) {
this.url = url;
}
@Override
public void run() {
String body = getWebData(url);
senior.thread_concurrent.handler.MyMessage msg = new senior.thread_concurrent.handler.MyMessage();
msg.obj = body;
mainHandler.sendMessage(msg);
}
}
//执行网络请求
private String getWebData(String url) {
LogUtil.print("执行请求网络:" + url);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String body = "这是" + url + "的响应值";
LogUtil.print("请求网络成功:" + body);
return body;
}
}
网友评论