Android 中的Handler详解

来源:互联网 发布:大数据对零售业的影响 编辑:程序博客网 时间:2024/06/06 05:02

Android 中的Handler详解

先看一下一个线程中使用Handler的步骤

        class MyThread extends Thread {                @Override                public void run() {                    Looper.prepare();                    MyHandler handler = new MyHandler();                    /**                     * do something                     */                    Looper.loop();//loop()要在最后调用                }        }
  1. 首先,我们要先调用Looper.prepare()方法,在这个方法中
    这里写图片描述
    会调用 prepare(boolean quitAllowed) 方法,在这个方法中我们能看到一行代码 sThreadLocal.set(new Looper(quitAllowed));,这个代码的意思就是 new一个Looper 放在当前线程的 ThreadLocal.Values 中,具体ThreadLocal.Values是什么东西,我们以后会解释,现在只需要理解为线程的一个成员变量,每个线程存储的都不一样

  2. 我们需要 new 一个自定义的Handler (继承自android.os.Handler,实现了handleMessage(Message msg)方法) ,下面就看一下自定义的MyHandler
    这里写图片描述

  3. 在这一步,我们就可以实现自己的逻辑,需要在这个线程中执行什么就写什么,没什么好说的

  4. 在我们的第四步,也是最最关键的一步,调用 Looper.loop(); 方法,首先说明这个方法是会阻塞的,也许会有人问,那阻塞之后岂不是线程就停在这了?确实是这样,所以会在最后一步调用这个方法,这个方法的作用就是要轮询 MessageQueue ,如果有新消息就交给 Handler 处理,下面就是 Looper.loop() 方法

     /** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the loop. */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;    // 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();    for (;;) {        Message msg = queue.next(); // might block        if (msg == null) {            // No message indicates that the message queue is quitting.            return;        }        // This must be in a local variable, in case a UI event sets the logger        Printer logging = me.mLogging;        if (logging != null) {            logging.println(">>>>> Dispatching to " + msg.target + " " +                    msg.callback + ": " + msg.what);        }        msg.target.dispatchMessage(msg);        if (logging != null) {            logging.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(TAG, "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.recycleUnchecked();    }}

从上面的代码中我们看到有这么一行代码 Message msg = queue.next(); // might block 源码中已经加了注释,说明这个方法可能会阻塞;感兴趣的可以找到 MessageQueue.next() 方法,看看里面代码的作用,我在这里直接告诉大家,这个方法是从MessageQueue中取消息,如果MessageQueue中没有消息,这段代码就会阻塞,取到消息之后我们看到有这么一行代码 msg.target.dispatchMessage(msg); msg.targetHandler,我们看一下 Handler.dispatchMessage(msg) 方法
这里写图片描述
这个就很好理解了,如果Message有callback,那么就执行Message的callback方法,mCallback是Handler的一个内部类,Handler有一个构造函数
这里写图片描述

需要的同学可以研究一下,这里不做过多解释
主要看一下 handleMessage(Message msg) 方法,这个方法是要在MyHandler中自己重写的,重写之后就能从别的线程中切换当前线程来执行代码

那么Handler如何将Message放在MessageQueue中呢

比如我们调用 Handler.sendMessage(Message msg) 方法,我们看一下源码
这里写图片描述

源码中调用了 sendMessageDelayed(Message msg, long delayMillis) 方法
这里写图片描述
这个函数中又调用了 sendMessageAtTime(Message msg, long uptimeMillis) 方法
这里写图片描述
好了,重磅炸弹来了,我们可以看到一行代码 return enqueueMessage(queue, msg, uptimeMillis); 看一下 enqueueMessage() 方法
这里写图片描述
终于我们找到了 MessageQueue.enqueueMessage(Message msg, long when) 方法,这是 MessageQueue 中方法,感兴趣的同学可以看一下这段代码,我就不贴上来了,这段代码的主要意思就是将一个新消息放在 MessageQueue 上,这样我们在上面调用 Looper.loop() 就能取到这个消息

至此,所有的你需要知道的Handler就这么多
下一节我们会讲解ThreadLocal

最后加上流程图,画的不好,请见谅

这里写图片描述

0 0