Handler原理浅析
理解Handler的原理首先要搞清楚什么是Looper,在我的上一篇博文中对此有专门的介绍。Looper的作用是开启一个消息循环,从MessageQueue(Message队列,是Looper的成员变量)中循环取出消息处理。一个线程要使用Handler来处理来自其它线程的消息,这个线程必须有且仅有一个Looper对象与之绑定,也可以说一个Looper对象是是与一个线程一一对应的。
Hander有一个Looper类型的成员,在Handler的构造函数(new Handler()或者new Handler(CallBack))中会实例化这个Handler的Looper成员,Handler()构造函数的源码如下:
publicHandler(){//获得当前线程在ThreadLocal中所对应的LoopermLooper=Looper.myLooper();if(mLooper==null){thrownewRuntimeException("Can'tcreatehandlerinsidethreadthathasnotcalledLooper.prepare()");}mQueue=mLooper.mQueue;mCallback=null;}
在Handler构造函数中实例化的Looper不是通过new关键字来实例化的,而是从Looper.myLooper()这个静态方法中取得的。而Looper.myLooper()又是从哪来取得的Looper对象呢?这就涉及到另外一个类ThreadLocal。Looper有一个静态变量是ThreadLocal类型的:
staticfinalThreadLocal<Looper>sThreadLocal=newThreadLocal<Looper>();
这个变量就是保存每一个线程和这个线程对应的Looper。这样设计的作用是保证每一个线程的Looper是唯一的。
每一个线程在new Handler()之前必须为这个线程创建Looper对象,使用Looper.prepare()方法创建。
Looper.prepare的源码如下:
publicstaticvoidprepare(){//调用此方法的线程是否在全局变量sThreadLocal(即Map<Thread,Looper>)中存有一组以此线程为键的键值对if(sThreadLocal.get()!=null){thrownewRuntimeException("OnlyoneLoopermaybecreatedperthread");}//如果在Map<Thread,Looper>中没有存放当前线程对应的键值对当存入//一个set操作,其实就是在Map中插入了一组<Thread,Looper>值,即<调用此方法的线程,newLooper()>//newLooper()时,Looper的构造函数就会实例化一个MessageQueue sThreadLocal.set(newLooper());
关键是sThreadLocal.set(new Looper());这条语句,它会把new 出来的Looper保存到ThreadLocal这个全局变量中。
有一个问题,就是为什么我们在主线程中new Handler(){...}之前不需要使用Looper.prepare()呢?因为在主线程执行之前,android虚拟机已经帮我们执行了这段代码,因此在主线程中创建Handler对象不需要再新建Looper对象。创建了Handler之后,还要使用Looper.loop()开启消息循环来取消息。主线程也不需要这句代码。
总结:
Looper负责开启消息循环,从MessageQueue中读取Message,由Handler负责处理读出来的Message。
Looper和它的MessageQueue与某一个线程是一一对应的。
使用Handler之前需要使用Looper.prepare()为当前线程创建Looper对象。
使用Looper.loop()开启消息循环。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。