Handler和Looper详解

关于这个话题,其实很早以前就想撰写相关来的妥当来加加深映像,或者当作技术笔记,可是一直都不知道从哪里开始比较合适.先看看网上给出的相关的定. 
Hanlder做用: 
1)执行计划任务,你能够再预约的实现执行某些任务,能够模拟定时器 
2)线程间通讯。在Android的应用启动时,会建立一个主线程,主线程会建立一个消息队列来处理各类消息。当你建立子线程时,你能够再你的子线程中拿到父线程中建立的Handler对象,就能够经过该对象向父线程的消息队列发送消息了。因为Android要求在UI线程中更新界面,所以,能够经过该方法在其它线程中更新界面。 


 
1、    角色描述 
1.Looper:(至关于隧道) 一个线程能够产生一个Looper 对象,由它来管理此线程里的Message Queue( 车队,消息隧道) 。 
2.Handler: 你能够构造Handler 对象来与Looper 沟通,以便push 新消息到Message Queue 里;或者接收Looper( 从Message Queue 取出) 所送来的消息。 
3.Message Queue( 消息队列): 用来存放线程放入的消息。 
4.线程:UI thread 一般就是main thread ,而Android 启动程序时会替它创建一个Message Queue 。 
每个线程里可含有一个Looper 对象以及一个MessageQueue 数据结构。在你的应用程序里,能够定义Handler 的子类别来接收Looper 所送出的消息。 

2、 执行过程 


当咱们在子线程建立一个Handler的时候,目的就是就能够经过该对象向父线程的 
消息队列发送消息了,那么这个handler对象是怎么实现的呢? 其实,当建立好一个Handler的时候,在Handler的构造方法中会得到一个主线程的消息队列监听器 —— Looper.这里简单说一下Looper,,咱们能够理解它为一个隧道或者是一直循环的监听器,咱们一般说的Looper都是主线程Looper,当主线程启动的时候,它会经过Looper的prepareMainLooper()方法,得到当前线程的Looper实例,而后让Looper调用loop方法不断地循环来处理message方法.看下面 



代码 

public static final void main(String[] args) { 
        SamplingProfilerIntegration.start(); 

        Process.setArgV0("<pre-initialized>"); 

        Looper.prepareMainLooper(); 
        if (sMainThreadHandler == null) { 
            sMainThreadHandler = new Handler(); 
        } 

        ActivityThread thread = new ActivityThread(); 
        thread.attach(false); 

        if (false) { 
            Looper.myLooper().setMessageLogging(new 
                    LogPrinter(Log.DEBUG, "ActivityThread")); 
        } 

        Looper.loop(); 



好吧,可能这里很难理解,因此咱们一点儿一点儿地来分析.而后再说handler怎么 
发挥做用的. 

先看 Looper.prepareMainLooper(),这里发生了什么? 

public static final void prepareMainLooper() { 
        prepare(); 
        setMainLooper(myLooper()); 
        if (Process.supportsProcesses()) { 
            myLooper().mQueue.mQuitAllowed = false; 
        } 
    } 

看上面的代码能够知道,首先Looper的prepareMainLooper()方法中调用了 prepare()方法,这个方法做用是赋予当前线程一个新的Looper对象,看代码: 

public static final void prepare() { 
        if (sThreadLocal.get() != null) { 
            throw new RuntimeException("Only one Looper may be created  
per thread"); 
        } 
        sThreadLocal.set(new Looper()); 
    } 

好了,明白了这个方法,那下一个方法setMainLooper(myLooper())呢? 继续看源代码!咱们先来看myLooper()方法. 

public static final Looper myLooper() { 
        return (Looper)sThreadLocal.get(); 
    } 

这个方法很简单,它的做用就是得到当前线程的Looper对象,前面咱们刚刚赋予了 一个Looper对象给当前线程,这里便获取了它,是否是有种遥相呼应的感受.. (再次声明,这里的当前线程指的是主线程或是UI线程),咱们再来看看 setMainLooper()方法:

private synchronized static void setMainLooper(Looper looper) { 
        mMainLooper = looper; 
    } 

也很简单,和以前的myLooper()方法就是把从当前线程得到Looper赋给一个mMainLooper的变量. 

好了,总结一下,Looper.prepareMainLooper();的做用就是咱们以前说的得到当前线程的Looper实例.下面再到 Looper.loop();看看 

public static final void loop() { 
        Looper me = myLooper(); 
        MessageQueue queue = me.mQueue; 
        
        // Make sure the identity of this thread is that of the local  
process, 
        // and keep track of what that identity token actually is. 
        Binder.clearCallingIdentity(); 
        final long ident = Binder.clearCallingIdentity(); 
        
        while (true) { 
            Message msg = queue.next(); // might block 
            //if (!me.mRun) { 
            //    break; 
            //} 
            if (msg != null) { 
                if (msg.target == null) { 
                    // No target is a magic identifier for the quit  
message. 
                    return; 
                } 
                if (me.mLogging!= null) me.mLogging.println( 
                        ">>>>> Dispatching to " + msg.target + " " 
                        + msg.callback + ": " + msg.what 
                        ); 
                msg.target.dispatchMessage(msg); 
                if (me.mLogging!= null) me.mLogging.println( 
                        "<<<<< Finished to    " + msg.target + " " 
                        + msg.callback); 
                
                // Make sure that during the course of dispatching the 
                // identity of the thread wasn't corrupted. 
                final long newIdent = Binder.clearCallingIdentity(); 
                if (ident != newIdent) { 
                    Log.wtf("Looper", "Thread identity changed from  
0x" 
                            + Long.toHexString(ident) + " to 0x" 
                            + Long.toHexString(newIdent) + " while  
dispatching to " 
                            + msg.target.getClass().getName() + " " 
                            + msg.callback + " what=" + msg.what); 
                } 
                
                msg.recycle(); 
            } 
        } 
    } 

这个方法看起来很复杂,其实咱们只须要关注里面关键的几个点就好了. 
1. Looper me = myLooper();刚才说过,就是得到当前线程(即主线程)的Looper. 

2. MessageQueue queue = me.mQueue;这个2.MessageQueue在前面已经作了详细 的介绍,因此就不作解释了,可是忽然出如今这里,有点莫名其妙......其实非也, 咱们能够看到queue是来至于me.mQueue,就是Looper中的一个成员变量,这个 queue是何时产生的呢? 其实还记得刚才的prepare() 方法么.这个方法中 实例化了一个Looper——new Looper().queue就是来自于Looper的构造方法,请 看代码就会明白了. 

private Looper() { 
        mQueue = new MessageQueue(); 
        mRun = true; 
        mThread = Thread.currentThread(); 
    } 

因此不是莫名其妙,是有根据的. 

3. Message msg = queue.next(),在循环体中看到的这段代码固然就是不断地将queue中的message一个一个地取出来啦! 

4. msg.target.dispatchMessage(msg);通过以前一系列的判断处理以后,来到了loop()方法中很是核心的地方,这里做用就是把这个从queue中得到的message分发给相应的地方来进行处理.好了。。。说了半天,终于能回到咱们开始说的Handler了. 

当时Handler怎么作才能和以前的步骤产生联系呢? Handler的使用咱们必须先实例化并实现它的handleMessage方法.呵呵,其实这个 只是一个引子......当咱们实例化Handler的时候其实就是和以前说过的Looper还有什么queue,产生联系的时候,继续看代码: 


  public Handler(Callback callback) { 
        if (FIND_POTENTIAL_LEAKS) { 
            final Class<? extends Handler> klass = getClass(); 
            if ((klass.isAnonymousClass() || klass.isMemberClass() ||  
klass.isLocalClass()) && 
                    (klass.getModifiers() & Modifier.STATIC) == 0) { 
                Log.w(TAG, "The following Handler class should be  
static or leaks might occur: " + 
                    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; 
        mCallback = callback; 
    } 

这下看Handler的构造方法是否是感受很轻松?那就好.....以前那么长的铺垫没有白费,若是还不懂,再结合者前面的讲解看几遍.总结下,当实例化一个Handler的时候,这个handler会得到主线程中的Looper对象,和Looper中的成员变量mQueue,好了,全部的拼图碎片已经筹齐咱们开始拼图了.咱们日常实例化了Handler是否是就可使用它的sendMessage方法呢?咱们看看sendMessage到底干了什么,它其实调用了一个sendMessageAtTime()方法. 

public boolean sendMessageAtTime(Message msg, long uptimeMillis) 
    { 
        boolean sent = false; 
        MessageQueue queue = mQueue; 
        if (queue != null) { 
            msg.target = this; 
            sent = queue.enqueueMessage(msg, uptimeMillis); 
        } 
        else { 
            RuntimeException e = new RuntimeException( 
                this + " sendMessageAtTime() called with no mQueue"); 
            Log.w("Looper", e.getMessage(), e); 
        } 
        return sent; 
    } 

哦.... 相信你们已经能明白了. 
首先msg.target = this;是否是很熟悉,我帮大家回忆一下.在Looper的looper的讲解中,第四个重点. 

msg.target.dispatchMessage(msg) 

是否是有种醍醐灌顶的感受.这下全部的拼图组成一张图了,从这句核心代码就明白了,主线程Looper负责把全部的Message分发给相对应的handler来处理,而后把这个Message再次放入队列.而target就是指的Handler.最后指定的Handler的HandleMessage来处理这个消息, 

这个就是整个Handler和Looper工做的流程....
相关文章
相关标签/搜索