handler机制

来源:互联网 发布:淘宝卖刀具犯法吗 编辑:程序博客网 时间:2024/06/14 08:36
Handler机制
一、Handler机制
Handler:
Looper:循环,消息循环
MessageQuene:消息队列,采用单链表的数据结构存储消息列表


ThreadLocal:在不同的线程中互不干扰的存储并提供数据,可以获取每个线程的Looper
主线程ActivityThread中有默认Looper,不需要创建
如要使用Handler,子线程中必须先创建Looper


主要为了解决在子线程中无法访问UI的矛盾(耗时操作在子线程中,更新UI在主线程中)
子线程不能访问UI的原因:
android的UI控件不是线程安全的,多线程并发导致UI控件处于不可预期


Looper运行在创建Handler的线程中


二、ThreadLocal
ThreadLocal:ThreadLocal为解决多线程程序的并发问题提供了一种新的思路
  当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
  从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。


ThreadLocal是如何做到为每一个线程维护变量的副本的呢?
其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。


三、MessageQuene
单链表的数据结构
插入:enqueueMassege,单链表的插入操作 data,node
读取(包含删除):next方法,是一个无线循环,如果 没有消息会一直堵塞,有的话会读取出来并从单链表中删除


四、Looper
消息循环,不停的查看MessageQuene是否有新消息
private Looper(){
  mQuene = new MessageQuene(quitAllowed);   //创建消息队列
  mthread = Thread.CurrentThread();
}


Looper.prepare():为当前线程创建一个looper
    sThreadLocal.set(new Looper(quitAllowed));   //
Looper.loop():开启消息循环,读取信息
msg.target.dispatchMessage(msg)回调


五、Handler
消息的发送:post,向Quene插入一条消息
接收及处理:dispatchMessage
        构造方法中:
        mLooper = Looper.myLooper();  
        if (mLooper == null) {  
            throw new RuntimeException(  
                "Can't create handler inside thread that has not called Looper.prepare()");  
        }  
        mQueue = mLooper.mQueue;  //得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue关联。
        mCallback = callback;  
        mAsynchronous = async; 
sendMessage(),msg的target赋值为handler自身加入队列中,
handleMessage():处理信息


六、主线程的消息循环




Message:
target:Handler target




到此,这个流程已经解释完毕,让我们首先总结一下
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不断从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
好了,总结完成,大家可能还会问,那么在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢,这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。








HandlerThread用法:


HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");
mHandlerThread.start();
        //把Handler和HandlerThread的Looper进行关联
mHandler = new Handler(mHandlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
System.out.println("Current Thread : " + Thread.currentThread());
}
};
mHandler.sendEmptyMessage(1);
}













































































原创粉丝点击