前篇总结:上一篇实现了用Looper管理消息队列和消息循环,但是消息的发送和消息处理都是在Looper中进行的。写一个子线程使用这样的Looper怎么才能获取到loop()死循环消息队列取出的消息呢?用回调!callBack!
第四节 仿写Handler来发送消息,实现回调接口,处理消息
Handler类的功能很简单:1.就是发送消息到本线程(Handler和Looper在同一个线程)的Looper对象的消息队列里。 2.实现消息回调方法处理消息。
public class TestThreadMsg5 {
public static Handler mainHandler;
public static void main(String[] args){
Looper.prepare();
mainHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
System.out.println("主线程:"+Thread.currentThread().getId()+" 收到消息:"+msg.obj);
if (msg.what == 1){
System.out.println("主线程:"+Thread.currentThread().getId()+" do work!");
System.out.println("");
System.out.println("");
}
return false;
}
});
Thread1 t1 = new Thread1();
t1.start();
Looper.loop();//阻塞式,死循环遍历消息列表
}
/**
* 模拟Handler,主要职责:
* 1.把消息放入到线程对应的Looper对象的消息队列里
* 2.处理消息
* Handler就是一个线程处理消息的钩子或者叫句柄,一个线程可以有很多个Handler实例
* 所以每个Message对象都有个target,指明消息对象由哪个Handler进行处理
* 而每个线程只允许有一个Looper对象与之对应,只有一个Looper对象自然也就只有一个消息队列了。
*
*/
public static class Handler {
Looper mLooper = null;
LinkedTransferQueue mQueue = null;
Callback mCallback = null;
//回调接口
public interface Callback {
public boolean handleMessage(Message msg);
}
public Handler(Callback callback) {
this.mLooper = Looper.myLooper();
this.mQueue = mLooper.mQueue;
this.mCallback = callback;
}
public void dispatchMessage(Message msg){
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
}
public final void sendMessage(Message msg){
msg.target = this;
mQueue.put(msg);
}
}
/**
* 消息实体类,主要职责:
* 1.承载消息内容
* 2.指定由谁来处理我(消息)
*/
static class Message {
public int what;
public Object obj;
public Handler target;//消息对应的Handler
}
/**
* 模拟Looper,主要职责:
* 1.创建管理消息队列
* 2.不断死循环取出消息队列里的消息
* 3.处理消息(后续交给Handler处理)
* 说明:Looper用静态prepare()方法实例化自己,每个线程只能实例化一个Looper对象
* Looper的myLooper()方法,在哪个线程调用就返回哪个线程的Looper对象(通过ThreadLocal实现)
*/
static class Looper{
//ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
LinkedTransferQueue mQueue;//阻塞式消息队列,每一个线程对应一个消息队列
private Looper(){
this.mQueue = new LinkedTransferQueue();//初始化阻塞式消息队列
}
/**
* 初始化Looper,并放到线程变量里,
* 这里做了限制,每个线程只能有一个Looper对象,因为是死循环多个也无意义
*/
public static void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
/**
* 从线程变量里取出,当前线程对应的Looper
* @return
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
/**
* 取出当前线程里的Looperd对象开始死循环遍历消息队列
*/
public static void loop(){
final Looper me = myLooper();
//模拟LOOP的循环方法
for (;;) {
Message msg = null;
try {
msg = (Message) me.mQueue.take();
msg.target.dispatchMessage(msg);//交个Message指定的Handler去处理
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public LinkedTransferQueue getQueue() {
return mQueue;
}
}
static class Thread1 extends Thread{
@Override
public void run() {
super.run();
for (;;) {
try {
Message msg = new Message();
msg.what = 1;
msg.obj = "主线程去更新UI吧";
System.out.println("子线程:"+Thread.currentThread().getId()+" 发送消息:"+msg.obj);
mainHandler.sendMessage(msg);//向主线程的Looper的消息队列里添加消息
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
首先说明下:1.在一个线程中可以有很多个Handler实例。 2.在线程中new Handler时 Handler会从Looper的myLooper()方法拿到当前线程的Looper对象,也顺便拿到Looper的Message队列。
Looper的loop()循环遍历出的消息怎么交给Handler处理的?答案就是消息实体类Message,Message中的target指定了该消息由哪个Handler对象处理。Looper调用Handler的dispatchMessage派送消息给Handler,Handler再通过回调给用户处理。
基本模拟了Android中的Handler、Looper线程通信,但是Android的MessageQueue不是用LinkedTransferQueue实现的,不过也是采用阻塞链表实现的有兴趣的可以看看。