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();        }    }}
原创粉丝点击