handler机制主要包含的类:
- Handler :负责发送和接收消息
- Message :消息承载体
- MessageQueue :存放消息的队列
- Looper :开启消息的轮询
为什么要在主线程更新UI?
答:系统设计者,为了考虑到用户体验,系统性能
子线程要更新UI,怎么办?
答:通过消息机制给主线程发送消息,让主线程更新UI,这个消息机制就是Handler
Handler只能用来更新UI吗?
答:Handler其实主要用来线程通信,
也就是可能会出现子线程和子线程通信的情况,那么轮询器Looper初始化就有可能出现在子线程中,
如何保证Looper对象能够在子线程中被正确获取,用于loop轮询呢?答案是ThreadLocal
ThreadLocal是什么?
答:ThreadLocal并不是一个Thread,而是Thread的局部变量。 ThreadLocal为解决多线程的并发问题而生。它使变量在每个线程中都有独立拷贝,不会出现一个线程读取变量时而被另一个线程修改的现象。
//这两个方法在哪个线程执行,hander就会在哪个线程接收消息
Looper.prepare();
Looper.loop();
复制代码
重点:
所以Handler不只是为了让子线程去更新UI,hander更重要的作用是可以用来线程间通信,正因为handler可以线程间通信才有了使用handler子线程发消息让主线程更新UI
模拟Hander: 简单手写Hander消息机制加深理解:
public class Message {
//target储存handerd对象
Handler target;
public int what;
public Object obj;
public Message(){ }
@Override
public String toString() {
return obj.toString();
}
}
复制代码
public class MessageQueue {
//互斥锁和条件变量
Lock lock;
Condition notEmpty;
Condition notFull;
Message[] items;
int putIndex;
int takeIndex;
int count;
public MessageQueue(){
this.items = new Message[50];
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
this.notFull = lock.newCondition();
}
/**
* 消息入队,生产者
* @param message
*/
public void enqueueMessage(Message message){
try {
lock.lock();
//队列满了,阻塞
while (count == items.length){
try {
notFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//入队
items[putIndex] = message;
//循环取值
putIndex = (++putIndex == items.length) ? 0 : putIndex;
count++; //元素计数
//有东西了,通知消费者消费
notEmpty.signalAll();
}finally {
lock.unlock();
}
}
/**
* 消息出队,消费者
* @return
*/
public Message next(){
Message msg = null;
try{
lock.lock();
while(count == 0){
try {
notEmpty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
msg = items[takeIndex];
items[takeIndex] = null;
//循环取值
takeIndex = (++takeIndex == items.length) ? 0 : takeIndex;
count--;
//又有新的空的位置,通知生产者生产
notFull.signalAll();
}finally {
lock.unlock();
}
return msg;
}
}
复制代码
public class Looper {
static ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
MessageQueue mQueue;
private Looper(){
mQueue = new MessageQueue();
}
/**
* 初始化当前线程的Looper对象
*/
public static void prepare(){
//一个线程对应一个Looper对象
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
/**
* 不断轮询队列中的消息
*/
public static void loop(){
Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
MessageQueue queue = me.mQueue;
for(;;){
Message msg = queue.next();
if(msg == null){
continue;
}
//转发
msg.target.dispatchMessage(msg);
}
}
/**
* 获取当前线程的Looper对象
* @return
*/
public static Looper myLooper(){
return sThreadLocal.get();
}
复制代码
public class Handler {
private Looper mLooper;
//消息队列
private MessageQueue mQueue;
public Handler() {
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
}
/**
* 发送消息
* @param msg
*/
public final void sendMessage(Message msg){
msg.target = this; //精妙之处,值得回味
mQueue.enqueueMessage(msg);
}
/**
* 转发消息
* @param msg
*/
public void dispatchMessage(Message msg){
handleMessage(msg);
}
/**
* 处理消息
* @param msg
*/
public void handleMessage(Message msg){
}
复制代码
写个Test类测试下我们刚刚写的Hander机制
public class Test {
public static void main(String[] args) {
//线程0:Thread-0
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
//在线程0中接受消息
final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
//接收到消息
System.out.println(Thread.currentThread().getName() + ",received:"+msg.toString());
}
};
//线程1:Thread-1
//在线程1中发消息
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
Message msg = new Message();
msg.what = i;
msg.obj = Thread.currentThread().getName() + ",send message:"+ UUID.randomUUID().toString();
System.out.println("send:"+msg);
handler.sendMessage(msg);
}
}
}).start()
Looper.loop();
}
}).start();
复制代码
打印语句:可以看到线程1发送的消息 都在线程0中接收到了
send:Thread-1,send message:ecb68c8c-97e9-43ef-8be6-b71f58b731d1
send:Thread-1,send message:1d18184f-4fef-4fdb-8485-b6e336e841c6
Thread-0,received:Thread-1,send message:ecb68c8c-97e9-43ef-8be6-b71f58b731d1
send:Thread-1,send message:9382768d-46f6-4d2b-95d8-c2bdff05b85d
Thread-0,received:Thread-1,send message:1d18184f-4fef-4fdb-8485-b6e336e841c6
Thread-0,received:Thread-1,send message:9382768d-46f6-4d2b-95d8-c2bdff05b85d
send:Thread-1,send message:78451cff-0e4f-4781-bdbd-6ad300f62ab9
send:Thread-1,send message:34536c77-8324-4c59-a179-00ce589de467
Thread-0,received:Thread-1,send message:78451cff-0e4f-4781-bdbd-6ad300f62ab9
Thread-0,received:Thread-1,send message:34536c77-8324-4c59-a179-00ce589de467
复制代码
如果是多个子线程发送消息呢?
public class Test {
public static void main(String[] args) {
//线程0:Thread-0
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
//线程0:Thread-0 在线程0中接受消息
final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
//接收到消息
System.out.println(Thread.currentThread().getName() + ",received:"+msg.toString());
}
};
for (int i = 0; i < 3; i++) {
//多个子线程发消息
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 3; i++) {
Message msg = new Message();
msg.what = i;
msg.obj = Thread.currentThread().getName() + ",send message:"+ UUID.randomUUID().toString();
System.out.println("send:"+msg);
handler.sendMessage(msg);
}
}
}).start();
}
Looper.loop();
}
}).start();
}
}
复制代码
打印语句:可以看到每个线程发送的消息都能在线程0中接收到了
send:Thread-3,send message:40ffbe1c-4234-4d4d-9ace-2433deab14d4
send:Thread-2,send message:f0f38098-86be-431d-962b-6e1029419ff2
send:Thread-1,send message:fe0f68a1-e91c-4840-a6d4-803ab3070e0a
Thread-0,received:Thread-3,send message:40ffbe1c-4234-4d4d-9ace-2433deab14d4
send:Thread-2,send message:a379f356-e9b2-4ccd-84a9-dabc211b826e
send:Thread-3,send message:3dbab897-00b6-4448-a78b-36455dca35aa
Thread-0,received:Thread-2,send message:f0f38098-86be-431d-962b-6e1029419ff2
Thread-0,received:Thread-1,send message:fe0f68a1-e91c-4840-a6d4-803ab3070e0a
send:Thread-3,send message:90446fe2-ecd7-4734-bf79-7a5ae9430c5c
Thread-0,received:Thread-2,send message:a379f356-e9b2-4ccd-84a9-dabc211b826e
Thread-0,received:Thread-3,send message:3dbab897-00b6-4448-a78b-36455dca35aa
Thread-0,received:Thread-3,send message:90446fe2-ecd7-4734-bf79-7a5ae9430c5c
send:Thread-1,send message:667286f0-d73e-4960-97de-37ae01ff3312
send:Thread-2,send message:49643caa-7bf7-4d60-88ca-115118dc9648
Thread-0,received:Thread-1,send message:667286f0-d73e-4960-97de-37ae01ff3312
Thread-0,received:Thread-2,send message:49643caa-7bf7-4d60-88ca-115118dc9648
send:Thread-1,send message:65782fb4-cc21-4366-a976-6c72d6128c2f
Thread-0,received:Thread-1,send message:65782fb4-cc21-4366-a976-6c72d6128c2f
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END