事件驱动线程


网上大把的资料都在说Android事件分发机制,什么Handler,Looper,我们也看了N+1遍了,面试也考了N+1次了。所以,我们对Handler的使用也是轻车熟路了。竟然那么简单,那么,接下来我们就来一起实现它。

  *  class LooperThread extends Thread {  *      public Handler mHandler;  *  *      public void run() {  *          Looper.prepare();  *  *          mHandler = new Handler() {  *              public void handleMessage(Message msg) {  *                  // process incoming messages here  *              }  *          };  *  *          Looper.loop();  *      }

执行完上面的伪代码后,我们的线程就变成了事件驱动线程,就是,我们发送一个事件,他才会工作,否则就会堵塞。这里用LinkedBlockingQueue来当作MessageQueue,并且LinkedBlockingQueue内部也是用链表实现的,只不过是双端链表,为了尽可能简单化…

实现


1、Message

public final class Message implements Serializable{    private Object obj;    private Handler mHandler;    public Object getObj() {        return obj;    }    public void setObj(Object obj) {        this.obj = obj;    }    public Handler getmHandler() {        return mHandler;    }    public void setmHandler(Handler mHandler) {        this.mHandler = mHandler;    }}

这个没什么好说的,比较简单。



2、Looper

public final class Looper {    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();    final LinkedBlockingQueue<Message> mQueue;     private static Logger logger = Logger.getLogger("Looper");    private Looper() {        mQueue = new LinkedBlockingQueue<Message>();    }    public static void prepare() {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper());        logger.info("Prepare....");    }    public static Looper myLooper() {        return sThreadLocal.get();    }    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 LinkedBlockingQueue<Message> queue = me.mQueue;        logger.info(queue==null?"没有获取到MessageQueue":"获取到了MessageQueue");        while(true){            try{                Message message = null;                try {                    message = queue.take();                    logger.info(message == null?"没有消息取出":"有消息取出");                } catch (InterruptedException e) {                    e.printStackTrace();                }                if(message != null){                    message.getmHandler().dispatchMessage(message);                    logger.info("处理消息...");                }            }catch(Exception e){                e.printStackTrace();            }        }    }}

当某个线程调用我们prepare()方法的时候,我们就会为它本地生成一个Looper对象,并且初始化一个MessageQueue,当入队列的时候,就是根据Looper对象找到MessageQueue的。当调用loop()方法的时候,Looper就开始一直轮循了,其中take()是一个堵塞方法,没有Message进入MessageQueue就一直堵塞。然后从Message中找到调用他的Handler,然后通过Handler分发消息。接下来的是Handler



3、Handler

public class Handler {    private CallBack callback;    private Looper mLooper;    private LinkedBlockingQueue<Message> mQueue;    public Handler() {        // TODO Auto-generated constructor stub        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(CallBack callback) {        mLooper = Looper.myLooper();        if (mLooper == null) {            throw new RuntimeException(                    "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;        this.callback = callback;    }    public Handler(Looper looper, CallBack callback) {        mLooper = looper;        mQueue = looper.mQueue;        this.callback = callback;    }    public interface CallBack{        boolean handleMessage(Message msg);    }    public void handleMessage(Message msg) {    }    public void dispatchMessage(Message msg) {        if (callback != null) {            if (callback.handleMessage(msg)) {                return;            }        }        msg.getmHandler().handleMessage(msg);    }    public void sendMessage(Message msg){        if(msg != null){            msg.setmHandler(this);        }        if(mQueue != null){            try {                mQueue.put(msg);            } catch (InterruptedException e) {                // TODO Auto-generated catch block                e.printStackTrace();            }        }    }}

Handler的生成很重要,如果无参的话,就要和Looper.prepare()同一个线程中生成,否则,就要自己传入looper,让Handler把消息丢入指定的队列中,因为上面Looper的分析可知,每个线程中维护了一个Looper对象,每个Looper对象又维护了一个MessageQueue对象。还有,在sendMessage()入队列的时候,要把自己传入给Message对象,等到处理的时候,就可以知道是谁调用的了,是谁调用的,就让谁处理。当然,我们也可以在构造Handler对象的时候,传入一个CallBack 对象,这样就不会默认执行handleMessage()方法了,就是我们实现CallBack接口的方法了。好的,下面来运行下,看看效果。



4、实现效果

public class Test {    private static Handler mHandler;    public static void main(String[] args) {        new Thread(){            public void run() {                Looper.prepare();                mHandler = new Handler(){                    @Override                    public void handleMessage(Message msg) {                        // TODO Auto-generated method stub                        super.handleMessage(msg);                        if(msg != null){                            System.out.println(msg.getObj());                        }                    }                };                Looper.loop();            };        }.start();        try {            TimeUnit.SECONDS.sleep(2);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        Message msg = new Message();        msg.setObj("消息处理机制~");        mHandler.sendMessage(msg);        try {            TimeUnit.SECONDS.sleep(2);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        Message msg1 = new Message();        msg1.setObj("消息处理机制~");        mHandler.sendMessage(msg1);    }}

下面是打印信息:

从另一种方式理解Android消息处理机制_第1张图片

更多相关文章

  1. Android 更新UI 只能在主线程?
  2. android 之对象传递
  3. android 消息机制与仿新闻客户端
  4. Android之Handler消息机制
  5. Android 并发工具类与线程池
  6. Android中Intent对象与Intent Filter过滤匹配过程详解
  7. android中的进程与线程
  8. Android线程处理简述

随机推荐

  1. Android客户端与PC服务器通过socket进行
  2. android页面布局时定义控件ID时@id/XX和@
  3. android,代码混淆,反编译,ADT 20版本
  4. Android功耗测试小工具集锦
  5. 与大家分享:【重磅】通付盾独家获得应用加
  6. Android(安卓)加载不同 DPI 资源与内存消
  7. 我的Android进阶之旅------>Android基于H
  8. Android下以root权限启动程序
  9. android 布局长度单位深入研究(2)
  10. android Canvas中的clipRect、drawBitmap