Handler和Message以及Looper之间的三角关系

说到Handler想必大家都经常用到,在非UI线程更新UI那可是利器,用起来也非常容易上手

从使用上来说,我们只需要关注sendMessage和handleMessage即可

所以我们先从Handler和Message来说起,先看一小段代码

    public static final int UPDATE_TEXT_VIEW = 0;
    public TextView mResultTextView = null;

    // new 一个 Handler 对象, 以内部类的方式重写 handleMessage 这个函数
    public Handler mMyHandler = new Handler() {
        // ③ 处理消息
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case UPDATE_TEXT_VIEW:
                    /* 这里可更新 ui */
                    mResultTextView.setText(String.valueOf(msg.arg1));
                    break;

                default:
                    /* do nothing */
                    break;
            }
        };
    };

    // ==================================================================
    // 函数名: calc
    // 日期: 2015-08-30
    // 功能: 计算入参并显示在 UI 上,然后后续以每秒 +1 在 UI 上更新
    // 输入参数: int a
    // int b
    // 返回值: 无
    // 修改记录:千里草新增函数
    // ==================================================================
    public void calc(int a, int b) {
        int c = a + b;
        final Message msg = new Message();
        msg.what = UPDATE_TEXT_VIEW;
        msg.arg1 = c;
        // ① 发送消息
        mMyHandler.sendMessage(msg);
        // 这里更新 UI 线程的TextView OK
        // mResultTextView.setText(String.valueOf(msg.arg1));

        // 启动一个新的线程来每秒刷新 TextView
        new Thread() {
            public void run() {
                while (true) {
                    msg.arg1++;
                    // ② 发送消息
                    mMyHandler.sendMessage(msg);

                    // mResultTextView.setText(String.valueOf(msg.arg1)); 这里会报错
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

            };
        }.start();
    }

代码中有①,②两处发送消息,. 分别是从UI线程和从子线程发送的消息, 在③处两个消息都可以被准确的接收到.

在接受消息函数handleMessage 里我们可以做任何想做的事情,包括更新UI…

从使用来说,大家根据这个例子,想必已经可以简单使用Handler来处理多线程之间的交互了…

此处需要注意的是在使用Handler时,必须需要重写handleMessage 才能达到我们想达到的目的...(从逻辑上来说,没有接受消息的地方,发送的消息有何意义呢,是吧….从原理上..我们接下来会谈到……)

谈到Handler,我们还可以用它执行一个Runnable多线程…例如下面的代码..

mMyHandler.post(new Runnable() {

            @Override
            public void run() {
                // 这里需要注意的是,calc 是在子线程里被调用,所以calc 就无法操作 UI 了.
                calc(1, 2);
            }
        });

Handler可真神奇,既可以发消息也可以执行某个任务线程.

为了更深层次的了解它,只能去看看它的源码了.let’s go!

先看看是如何post一个Runnable线程的

public final boolean post(Runnable r)
    {
       //这里实际上是发送了一个Message
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

    //组装一个只带Runnable的Message
    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    //发送消息
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

哎哟喂,这Handler小丫头片子,还假装两幅面孔呢, 经查看源码,发现它实际上是发送了一个Message消息,然而这个消息仅仅携带了一个Runnable对象.

现在来看只需要分析Handler和Message了..我们来看看最终Handler是如何发送消息的..我们继续看源码,非得把他们扒个精光不可

public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        //消息队列,这里存储Handler发送的消息
        MessageQueue queue = mQueue;
        if (queue != null) {
            //Message与Handler绑定
            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;
    }

从消息最终被发出的函数来看,这里只做了两个事情:

1.Message与Handler绑定

2.将Message放进消息队列里

消息进队列之后,Handler发送消息的任务算是完美的完成了,接下来我们该介绍介绍Looper了,如果没有Looper,Handler和Message之间的爱情可以说是不完整的.

我们先来看看一个Looper是如何使用的吧

class LooperThread extends Thread {
            public Handler mHandler;

            public void run() {
                // 为当前线程准备一个 Looper
                Looper.prepare();

                mHandler = new Handler() {
                    public void handleMessage(Message msg) {
                        // 处理消息
                    }
                };
                // Looper 开始工作
                  Looper.loop();
            }
        }
    //继续看源码,prepare执行之后sThreadLocal绑定一个Looper对象
    //sThreadLocal 能且只能绑定一个Looper对象
    public static void prepare() {
        prepare(true);
    }

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

    /**
     * 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循环,来遍历Messagequeue
        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);
            }

            //Message绑定的Handler来开始处理消息.. 下面贴上dispatchMessage,函数,大家继续往下看
              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.recycle();
        }
    }
    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     */
    public interface Callback {
        public boolean handleMessage(Message msg);
    }

    /**
     * Subclasses must implement this to receive messages.
     * 子类必须完成handleMessage这个函数来接收消息
     */
    public void handleMessage(Message msg) {
    }

    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        //收到消息后,先处理Runnable 对象callback.
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            //如果这里有回调接口,那么就直接调用该接口,不再继续调用Handler的handleMessage函数来处理消息
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

从上述加了中文注释的代码中能看出,Handler发送的Message通过Looper分发给了各自的Handler.

所以上面说的在使用Handler时,必须需要重写handleMessage 才能达到我们想达到的目的...也不完全正确,

我们也可以实现一个CallBack接口来处理消息,用Google的原话是

    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     */
    public interface Callback {
        public boolean handleMessage(Message msg);
    }

再贴最后一段代码来彻彻底底说明Handler Looper之间的关系, 那就是Handler的 构造函数

/**
     * Default constructor associates this handler with the queue for the
     * current thread.
     *
     * If there isn‘t one, this handler won‘t be able to receive messages.
     */
    public Handler() {
        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());
            }
        }
        //绑定当前线程的Looper
        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 = null;
    }

一句话总结来说,Handler初始化时绑定了线程的MessageQueue,当前线程的Looper来依次分发MessageQueue里的消息.

MessageQueue的消息会根据Message的target绑定的Handler被Looper分发到各自的Handler里去处理.

例如Activity里有两个HandlerA和HandlerB, HandlerA发送的消息绝对不可能被HandlerB处理..

先暂时写到这里吧,后续补上流程图和类图

上述只是个人的很片面的理解,希望大家补充和指出不足的地方…

2015年9月4日 04:10:05 千里草

时间: 2024-10-22 07:08:39

Handler和Message以及Looper之间的三角关系的相关文章

Handler Message MessageQueue Looper 之间的联系

Handler Message MessageQueue Looper 之间的联系

Android 消息机制 (Handler、Message、Looper)

综合:http://blog.csdn.net/dadoneo/article/details/7667726 与 http://android.tgbus.com/Android/androidnews/201204/421642.shtml 一. 消息机制常用类的介绍和使用 在Android程序运行中,线程之间或者线程内部进行信息交互时经常会使用到消息,如果我们熟悉这些基础的东西及其内部的原理,将会使我们的Android开发变的容易.可以更好地架构系统.在学习Android消息机制之前,我们

Android面试题 请解释下单线程模型中Message、Handler、MessageQueue、Looper之间的关系

简单的说,Handler获取当前线程中的looper对象,looper用来存放从MessageQueue中取出的Message,再由Handler进行Message分发和处理,按照先进先出执行. MessageQueue(消息队列):用来存放通过Handler发送的消息,通常附属于某一个创建它的线程,可以通过Looper.myQueue()得到当前线程的消息队列. Handler:是Message的主要处理者,负责Message的发送,Message内容的执行处理.例如将消息发送到消息队列(se

单线程模型中Message、Handler、MessageQueue、Looper之间的关系

Handler简介: 一个Handler允许你发送和处理Message和Runable对象,这些对象和一个线程的MessageQueue相关联.每一个线程实例和一个单独的线程以及该线程的MessageQueue相关联.当你创建一个新的Handler时,它就和创建它的线程绑定在一起了.这里,线程我们也可以理解为线程的MessageQueue.从这一点上来看,Handler把Message和Runable对象传递给MessageQueue,而且在这些对象离开MessageQueue时,Handler

Android开发学习之路--异步消息Handler,Message,Looper和AsyncTask之初体验

在简易音乐播放器中,用了Handler,也没有过多地去研究学习,这里再学习下android下的异步消息处理机制.这里用了Handler主要是在线程中不能更新UI,而需要通过Handler才可以.关于异步消息处理有几个概念. 1.Message:消息,线程间通讯的数据单元.例如后台要下载歌曲然后下载完成要更新ui,则可以发送一条包含更新信息的Message给UI线程. 2.MessageQueue:消息队列,用来存放所有通过Handler发布的消息,因为是队列,所以是先进先出的. 3.Handle

[Android源代码分析]Android消息机制,Handler,Message,Looper,MessageQueue

最近准备把Android源码大致过一遍,不敢私藏,写出来分享给大家,顺便记录一下自己的学习感悟.里面一定有一些错误的地方,希望广大看客理解理解. 网上也有不少分析文章,这里我尽量分析的更加细致详尽.不留死角. 一.核心循环体:Looper.loop(); 我们知道,在线程run()中Looper.prepare();Looper.looper().之后这个线程就是一个HandlerThread了.我们可以通过Handler在另外一个线程中(自己也可以)向这个线程发送消息,在这个线程中处理消息.

在单线程模型中 Message、Handler、Message Queue、Looper 之间的关系

Message,信息的载体,用来传递数据给Handler. Handler (Handler处理者,是 Message 的主要处理者,负责 Message 的发送,Message 内容的执行处理)发送和处理Message和Runable对象,这些对象和一个线程的MessageQueue相关联.每一个线程实例和一个单独的线程以及该线程的 MessageQueue 相关联.Handler和创建它的线程绑定在一起,把 Message和Runable 对象传递给 MessageQueue,这些对象离开

Message、Handler、Message Queue、Looper 之间的关系

单线程模型中Message.Handler.Message Queue.Looper之间的关系 1.Message Message即为消息,可以理解为线程间交流的信息.处理数据后台线程需要更新UI,你可以发送Message内含一些数据给UI线程. 2.Handler Handler 即为处理者,是Message的主要处理者,负责Message的发送,Message内容的执行处理. 后台线程就是通过传进来的Handler对象引用来sendMessage(Message).而使用Handler,需要

Message、Handler、Message Queue、Looper、Thread之间的关系(未完成)

1. 请解释下在单线程模型中Message.Handler.Message Queue.Looper.Thread之间的关系 2. 什么是IntentService?有何优点? 1) 它是对单线程消息模型的封装 2)IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker t