之前研究过Android的Handler机制,但是一直没有机会自己实现一次。最近又看到这个Handler机制,于是决定自己实现以下这个Handler机制。
首先,简单介绍以下Handler机制。
Handler机制在Android中通常用来更新UI:子线程执行任务,任务执行完毕后发送消息:Handler.sendMessage(),然后在UI线程Handler.handleMessage()就会调用,执行相应处理。
Handler机制有几个非常重要的类:
Handler:用来发送消息:sendMessage等多个方法,并实现handleMessage()方法处理回调(还可以使用Message或Handler的Callback进行回调处理,具体可以看看源码)。
Message:消息实体,发送的消息即为Message类型。
MessageQueue:消息队列,用于存储消息。发送消息时,消息入队列,然后Looper会从这个MessageQueen取出消息进行处理。
Looper:与线程绑定,不仅仅局限于主线程,绑定的线程用来处理消息。loop()方法是一个死循环,一直从MessageQueen里取出消息进行处理。
按照上面介绍的4个重要组成类,从内向外依次自定义相应的类,实现Handler机制。
MyMessage类:
public class MyMessage {
private int code;
private String msg;
MyHandler target;
public MyMessage(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
MessageQueue类:(由于该类可以有多种实现方式,所以在此定义一个接口)
public interface IMyMessageQueue {
MyMessage next() throws InterruptedException;
void enqueueMsg(MyMessage msg) throws InterruptedException;
}
从Android源码中了解到,这个MessageQueue是一个队列,所以在此简单的已一个BlockingQueue队列来实现消息的进队出队操作:
public class MyBlockingQueue implements IMyMessageQueue {
private BlockingQueue mQueue;
public MyBlockingQueue(int init) {
this.mQueue = new LinkedBlockingDeque<>(init);
}
@Override
public MyMessage next() throws InterruptedException {
return mQueue.take();
}
@Override
public void enqueueMsg(MyMessage msg) throws InterruptedException {
mQueue.put(msg);
}
}
MyLooper类:持有一个MyMessageQueue实例,并使用ThreadLocal绑定当前线程,启动一个死循环。
public class MyLooper {
private static final ThreadLocal THREAD_LOCAL = new ThreadLocal<>();
IMyMessageQueue mMessageQueue;
private static MyLooper mMainLooper;
public MyLooper() {
mMessageQueue = new MyBlockingQueue(4);
}
public static void prepare() {
if (null != THREAD_LOCAL.get()) {
throw new RuntimeException("Only one looper can be created per thread.");
}
THREAD_LOCAL.set(new MyLooper());
}
public static void prepareMainLooper() {
prepare();
synchronized (MyLooper.class) {
if (null != mMainLooper) {
throw new RuntimeException("MainLooper has already been prepared.");
}
mMainLooper = myLooper();
}
}
public static void loop() {
final MyLooper looper = myLooper();
if (null == looper) {
throw new RuntimeException("No looper! MyLooper.prepare() wasn't called on this thread.");
}
for (; ; ) {
MyMessage msg = null;
try {
msg = looper.mMessageQueue.next();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (null != msg) {
msg.target.handleMessage(msg);
}
}
}
public static MyLooper getMainLooper() {
return mMainLooper;
}
public static MyLooper myLooper() {
return THREAD_LOCAL.get();
}
}
MyHandler类:持久消息队列,并定义一个抽象方法,负责发送和处理消息。
public abstract class MyHandler {
private IMyMessageQueue mQueue;
public MyHandler(MyLooper looper) {
mQueue = looper.mMessageQueue;
}
public MyHandler() {
MyLooper.myLooper();
}
public void sendMessage(MyMessage msg) {
msg.target = this;
try {
mQueue.enqueueMsg(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public abstract void handleMessage(MyMessage msg);
}
到此,自定义Handler功能代码实现,下面测试一下启动MyMainLooper,并在子线程中使用MyHandler发送和处理消息。
TestMyHandler
public class TestMyHandler {
@Test
public void test() {
MainThread mainThread = new MainThread();
mainThread.start();
while (null == MyLooper.getMainLooper()) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
MyHandler handler = new MyHandler(MyLooper.getMainLooper()) {
@Override
public void handleMessage(MyMessage msg) {
switch (msg.getCode()) {
case 1:
System.out.print(msg.getMsg() + "在" + Thread.currentThread().getName() + "上执行!\r\n");
break;
case 2:
System.out.print(msg.getMsg() + "在" + Thread.currentThread().getName() + "上执行!\r\n");
break;
}
}
};
new Thread(() -> {
MyMessage myMessage = new MyMessage(1, "子线程消息1");
handler.sendMessage(myMessage);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
MyMessage myMessage2 = new MyMessage(2, "子线程消息2");
handler.sendMessage(myMessage2);
}).run();
}
/**
* 主线程
*/
public class MainThread extends Thread {
public MainThread() {
setName("MainThread");
}
@Override
public void run() {
MyLooper.prepareMainLooper();
System.out.print(getName() + "has been prepared.\r\n");
MyLooper.loop();
}
}
}