Java代码实现安卓Handler
来源:互联网 发布:买网络电视什么牌子好 编辑:程序博客网 时间:2024/06/08 03:04
Handler机制的写法非常巧妙,这种逻辑方式不仅仅对于安卓,对于其它的windows应用、Swing开发都有可以借鉴的地方,之前还在做安卓的时候就一直很想把代码分离出来。
这里,我就简单地实现了Handler的主要功能,并没有做很细致的配置。代码的整体结构完全参考了Handler(或者说是直接拷贝的),具体的实现中,消息队列使用的是PriorityQueue,并且多了Delayed对象的使用。
只要你用的还是Java,在JDK1.5之后任何地方都可以使用。
PriorityQueue队列计时元素
这个类不仅局限于本次代码,同样适用于java.util.concurrent包下其它通过PriorityQueue实现的队列。
此元素标明了每个消息的延迟时间,模仿了Handler发送延迟消息的功能。
import java.util.concurrent.Delayed;import java.util.concurrent.TimeUnit;import java.util.concurrent.TimeoutException;/** * 延迟队列元素 * * @author ChenSS on 2017年9月13日 * @param <T> */public class DelayItem<T> implements Delayed { private long timeout; private long endTime; private T item; public DelayItem(T item, long timeout) { this.item = item; this.timeout = timeout; this.endTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS); } public DelayItem(T item, long timeout, TimeUnit unit) { this.item = item; this.timeout = timeout; this.endTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, unit); } public T getItem() { return this.item; } public long getTimeout() { return timeout; } /** * 重置结束时间 */ public void reset() throws TimeoutException { if (System.nanoTime() > endTime) throw new TimeoutException("The current object has timeout, can not be reset"); this.endTime = System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS); } /** * 预计结束时间-当前时间 = 剩余停滞时间(当数值小于零时此对象可用) * * @return 纳秒(未达到超时时间对象不可用) */ @Override public long getDelay(TimeUnit unit) { return unit.convert((endTime - System.nanoTime()), TimeUnit.NANOSECONDS); } /** * 取出结束时间最早的 */ @Override public int compareTo(Delayed other) { if (other == this) return 0; if (other instanceof DelayItem) { long diff = endTime - ((DelayItem<?>) other).endTime; return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1); } long diff = (getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS)); return (diff == 0) ? 0 : ((diff < 0) ? -1 : 1); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((item == null) ? 0 : item.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; DelayItem<?> other = (DelayItem<?>) obj; if (item == null) { if (other.item != null) return false; } else if (!item.equals(other.item)) return false; return true; }}
Handler
源码直接拷贝自安卓的Handler,删除了对于我来说不需要的代码。
package com.yt.test.handler;public abstract class Handler { public Looper mLooper; public MessageQueue mQueue; public Handler() { final Class<? extends Handler> klass = getClass(); // java.lang.Class.isAnonymousClass() 当且仅当底层类是匿名类,则返回true。 // java.lang.Class.isMemberClass() 返回true当且仅当底层类是成员类。 // java.lang.Class.isLocalClass()返回true,当且仅当基础类是局部类。 // 原本这是日志,说明Handler不要随便去new,容易内存溢出 if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass())) { System.out.println("The following Handler class should be static or leaks might" + " + klass.getCanonicalName()"); } mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()"); } mQueue = mLooper.mQueue; } public Handler(Looper looper) { } public final boolean sendMessage(Message msg) { return sendMessage(msg, 0); } public final boolean sendMessage(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessage(msg, delayMillis); } public final boolean sendMessage(Message msg, long delayMillis) { if (delayMillis < 0) delayMillis = 0; return sendMessageAtTime(msg, delayMillis); } public boolean sendMessageAtTime(Message msg, long delayMillis) { MessageQueue queue = mQueue; if (queue == null) throw new RuntimeException(this + " sendMessageAtTime() called with no mQueue"); return enqueueMessage(queue, msg, delayMillis); } private boolean enqueueMessage(MessageQueue queue, Message msg, long delayMillis) { msg.target = this; return queue.enqueueMessage(msg, delayMillis); } public final void dispatchMessage(Message msg) { handleMessage(msg); } abstract public void handleMessage(Message msg);}
Looper
package com.yt.test.handler;public class Looper { static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); public MessageQueue mQueue = new MessageQueue(); public Thread mThread; private Looper() { } private Looper(boolean quitAllowed) { mThread = Thread.currentThread(); } public static Looper myLooper() { return sThreadLocal.get(); } public static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); } public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; for (;;) { try { Message msg = queue.next(); if (msg == null) return; msg.target.dispatchMessage(msg); } catch (InterruptedException e) { e.printStackTrace(); } } }}
Message
package com.yt.test.handler;public class Message { private static final Message MESSAGE = new Message(); public Handler target; // 变量,用于定义此Message属于何种操作 public int what; // 变量,用于定义此Message传递的信息数据,通过它传递信息 public Object obj; // 变量,传递一些整型数据时使用 public int arg1; // 变量,传递一些整型数据时使用 public int arg2; public static Message obtain() { return MESSAGE; }}
MessageQueue
使用了锁和优先级队列,
优先级队列的使用,对比每一个消息的延迟时间,取出最着急等待的消息;
锁主要用于阻塞线程,虽然取出了最着急等待的那个消息,如果系统时间没有达到可以处理这个消息的时间,那么就阻塞线程,等待时间的到达。
这是为了实现Handler发送延迟消息的功能。
package com.yt.test.handler;import static java.util.concurrent.TimeUnit.NANOSECONDS;import java.util.PriorityQueue;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class MessageQueue { private final transient ReentrantLock lock = new ReentrantLock(); private final PriorityQueue<DelayItem<Message>> q = new PriorityQueue<>(); private final Condition available = lock.newCondition(); private Thread leader = null; public Message next() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { for (;;) { DelayItem<Message> first = q.peek(); if (first == null) available.await(); else { long delay = first.getDelay(NANOSECONDS); if (delay <= 0) { first = q.poll(); return first.getItem(); } first = null; // don't retain ref while waiting if (leader != null) available.await(); else { Thread thisThread = Thread.currentThread(); leader = thisThread; try { available.awaitNanos(delay); } finally { if (leader == thisThread) leader = null; } } } } } finally { if (leader == null && q.peek() != null) available.signal(); lock.unlock(); } } public boolean enqueueMessage(Message msg, long uptimeMillis) { final ReentrantLock lock = this.lock; DelayItem<Message> item = new DelayItem<Message>(msg, uptimeMillis); lock.lock(); try { q.offer(item); if (q.peek() == item) { leader = null; available.signal(); } return true; } finally { lock.unlock(); } }}
参照安卓的调用方式
如果你想写一个windows应用,写Swing啊什么的,就用这样的方式实现
package com.yt.test.handler;public class Test { public static Handler sMainThreadHandler; public static void main(String[] args) { // 启动looper Looper.prepare(true); // 创建一个子线程(工作线程,比如加载Activity啊,初始化一堆的对象等等) startWorkThread(); // 创建一个子线程与主线程通讯的处理器,有需要主线程处理的事情,子线程就通过这个Handler发消息 sMainThreadHandler = initMainHandler(); // 启动主线程的无限轮询 Looper.loop(); } public static Handler initMainHandler() { return new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { //TODO: 处理不同的消息(安卓中是一堆类型强转跟消息传递的代码) default: // EG:创建一个新的Handler Test.createActivity(); break; } } }; } public static void startWorkThread(){ new Thread(() -> { try { //延迟,确保Lopper进入循环 Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+ " :send msg"); //假设说子线程的作用就是发送消息,要主线程new一个Handler sMainThreadHandler.sendMessageAtTime(new Message(), 3000); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } public static void createActivity() { Handler handler = new Handler() { @Override public void handleMessage(Message msg) { System.out.println(Thread.currentThread().getName()+ " :get msg"); } }; System.out.println(Thread.currentThread().getName()+ " :send msg"); handler.sendMessage(new Message()); }}
其实还可以很多的事情
比如说你要一个记日志的Handler啊,输出SQL语句的Handler啊,都可以,Looper从没说非得跑在主线程,你可以使用Looper写一个专门的LooperThread。
package com.yt.test.handler;public class Test2 { static Handler handler1; static Handler handler2; public static void main(String[] args) { Thread handlerThread = new Thread(new Runnable() { @Override public void run() { Looper.prepare(true); handler1 = new Handler() { @Override public void handleMessage(Message msg) { System.out.println("handler1 LOG:" + msg.obj); } }; handler2 = new Handler() { @Override public void handleMessage(Message msg) { System.out.println("handler2 SQL:" + msg.obj); } }; Looper.loop(); } }); handlerThread.setName("handlerThread"); handlerThread.setDaemon(true); handlerThread.start(); try { Thread.sleep(3000); int count = 30; while (count-- > 0) { final int cn = count; new Thread(() -> { Message message = new Message(); String msg = "[" + Thread.currentThread().getName() + "]" + cn; message.obj = msg; if (cn % 2 == 0) { handler1.sendMessage(message); } else { handler2.sendMessage(message); } }, "THREAD" + count).start(); } } catch (InterruptedException e) { e.printStackTrace(); } }}
阅读全文
0 0
- Java代码实现安卓Handler
- 安卓java代码动态实现Selector
- 安卓Handler实例
- 安卓 Handler使用方法
- 安卓handler释义
- 安卓handler详解
- 安卓handler学习
- 安卓handler
- 安卓学习-Handler
- 安卓学习-Handler
- 安卓Handler详解
- 安卓Handler机制
- 安卓动画代码实现
- 安卓实现代码混淆
- 安卓实现代码混淆
- 采用Handler的postDelayed实现安卓定时器
- 安卓:Handler实现图片轮播(非ViewPager)
- 安卓倒计时(android.os.Handler.Handler()
- 微信小程序支付申请
- 浅析MySQL中的explain参数
- R6 STM32 I2C—读写EEPROM
- day06-js入门
- 如何统计一天24小时每个小时的数据量
- Java代码实现安卓Handler
- 一个简单的socket服务端Demo
- 复制文本内容到系统剪贴板(自由复制)(android开发)
- 05-定位 position absolute
- JAVA单例设计模式
- LeetCode Problem 11 Container With Most Water解题报告
- 记录pip3安装报错:[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:645) 。。。
- 关于重写servlet的service()方法时调用父类service方法的问题
- Appium配置安装遇到的问题