handler原理分析及模仿handler实现简单主/子线程通信架构
2017-06-12 00:39
936 查看
1、分析handler原理
主线程和子线程通信通常靠Handler,要实现通信,需要Handler、MessageQueue、Message、Looper用图表示
每个Handler都有一个Looper对象,而Looper对象的生成过程是
//sThreadLocal.get() will return null unless you've called prepare() static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<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对象是保存在ThreadLocal当中。
ThreadLocal用于线程间的数据隔离,保证数据安全。
给当前线程关联一个Looper对象。
sThreadLocal.set(new Looper());
在android程序的入口ActivityThread中,默认为主线程关联了一个Looer对象,所以在调用Handler时,我们不用自己给主线程关联Looper对象,也就是Looper.prepare()
ActivityThread.java
public static void main(String[] args) { ... Looper.prepareMainLooper(); ... Looper.loop() }
Looper.java中
public static void prepareMainLooper() { prepare(); ... }
2、模范Handler实现主/子线程通信
新建Handler.javapackage com.handler; /** * Created by Tony on 2017/6/11. */ public class Handler { private MessageQueue mQueue; //Handler的初始化在主线程中完成 public Handler() { //获取主线程的Looper对象 this.mQueue = Looper.myLooper().mQueue; } /** * 发送消息,压入队列 * @param msg */ public void sendMessage(Message msg) { msg.target = this; mQueue.enqueueMessage(msg); } public void dispatchMessage(Message msg) { handleMessage(msg); } public void handleMessage(Message msg) { } }
新建Looper文件
package com.handler; /** * Created by Tony on 2017/6/11. */ public final class Looper { //每一个主线程都有一个Looper对象 //Looper对象保存在ThreadLocal,保证了线程数据的隔离 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //一个Looper对象对应一个消息队列 MessageQueue mQueue; private Looper() { mQueue = new MessageQueue(); } 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(); } /** * 轮询消息队列 */ public static void loop() { Looper me = myLooper(); if (me == null) { throw new RuntimeException(""); } MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); if (msg == null) { continue; } //转发给Handler msg.target.dispatchMessage(msg); } } }
新建MessageQueue
package com.handler; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Created by Tony on 2017/6/11. */ public class MessageQueue { /** * 消息队列应该要有大小限制 * 消息队列满了,子线程停止发送消息,阻塞 * 消息队列为空,主线程Looper停止轮循,阻塞 */ //通过数组的结构存储Message对象 Message[] items ; //入队与出队元素索引位置 int putIndex; int takeIndex; //计数器 int count; //互斥锁 private Lock lock; //条件变量 private Condition notEmpty; private Condition notFull; public MessageQueue() { this.items = new Message[50]; this.lock = new ReentrantLock(); this.notEmpty = lock.newCondition(); this.notFull = lock.newCondition(); } /** * 入队列(子线程运行) * @return */ public void enqueueMessage(Message msg) { try { lock.lock(); //消息队列满了,子线程挺好i发送消息,阻塞 while (count == items.length) { try { notFull.await(); } catch (InterruptedException e) { e.printStackTrace(); } } items[putIndex] = msg; //循环取值 putIndex = (++putIndex == items.length) ? 0:putIndex; count++; //有新的Message对象,通知主线程 notEmpty.signal(); } finally { lock.unlock(); } } /** * 出队列(主线程运行) * @return */ public Message next() { Message msg = null; try { //消息队列为空,主线程Looper停止轮询,阻塞 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--; //使用了一个的Message对象,通知子线程,可以继续生产 notFull.signal(); } finally { lock.unlock(); }
这里写代码片
新建Message.java
package com.handler; /** * Created by Tony on 2017/6/11. */ public class Message { Handler target; public int what; public Object obj; @Override public String toString() { return obj.toString(); } } return msg; } }
新建测试文件HandlerTest.java
package com.handler; import java.util.UUID; /** * Created by Tony on 2017/6/12. */ public class HandlerTest { public static void main(String[] args) { //轮询器初始化 Looper.prepare(); //主线程 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 < 10; i++) { new Thread(new Runnable() { @Override public void run() { while (true) { Message msg = new Message(); msg.what = 1; synchronized (UUID.class){ //加锁,线程安全 msg.obj = Thread.currentThread().getName() +",send message:"+ UUID.randomUUID().toString(); } handler.sendMessage(msg); System.out.println(msg); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } //开始轮询 Looper.loop(); } }
测试结果如下:
以上用了较简单的方式实现了主线程和子线程的通信。
源码地址:
https://github.com/fsdsds/HandlerDemo
相关文章推荐
- Android Handler如何实现线程间通信,源码分析。
- Android中线程间通信原理分析:Looper,MessageQueue,Handler
- Android线程通信:Handler,MessageQueue和Looper原理分析
- 源码分析Android Handler是如何实现线程间通信的
- handler实现线程间通信的原理-looper
- Android中线程间通信原理分析:Looper,MessageQueue,Handler
- Handler实现线程间通信的原理
- Android 中线程间通信原理分析:Looper, MessageQueue, Handler
- 源码分析Android Handler是如何实现线程间通信的
- 控制反转(IOC)的简单实现及原理分析
- 【转】【简单Web服务器搭建】基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
- 一个App架构例子分析--UI层使用MVP模式;各层之间使用Otto实现通信
- 实现采用客户/服务器通信模式,基于TCP网络通信协议的多客户端简单应用之案例分析
- 【简单Web服务器搭建】基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
- 也谈WEB打印(二):简单的分析一下IE的打印原理并实现
- gtest实现架构简单分析
- 细说jQuery原型的创建和实现原理,并用实例简单模仿
- PHP的MVC模式实现原理分析(一相简单的MVC框架范例)
- 【简单Web服务器搭建】基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
- OpenStack建立实例完整过程源码详细分析(13)----依据AMQP通信架构实现消息发送机制解析之二