android消息处理之Handler

原创 2016年08月28日 15:16:28

最近在公司分享了消息处理都线程,同时阅读了Handler的源码,特此记录下来,并分享自己demo。首先,我们知道Handler是用来处理消息和发布消息的,而Looper是负责Handler和Thread之间的桥梁,Messagequeen是消息队列,Looper负责将消息不断传递给Handler的回调函数。


 public Handler(Callback callback, boolean async) {
        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,即获取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 = callback;
        mAsynchronous = async;
    }

实例化Handler目的就是为了获取到Looper,因为Looper是Handler和线程之间的纽带,同时负责Message的管理工作,继续向下阅读分析Looper中,myLooper是如何让Handler关联到线程的。

    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));
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

  //省略部分代码
 /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }


可以看到在myLooper中,来获得Looper,但是这里面的Looper是什么时候设置进去的?是在上面prepare中,同时可以看出,线程是和Looper之间有着直接的联系。所以,在子线程中,为了调用handler,通常要先调用prepare,就是为了先将Looper设置到线程,和线程建立连接。在子线程中,光调用prepare是不够的,还必须调用loop(),下面来看下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();//1、取得到Looper
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;//2、获取消息队列

        // 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 (;;) {                         //3、进入死循环
            Message msg = queue.next(); // 4、遍历消息
            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);  //5、调用handler的方法,因此我们在实例化Handler的时候,要重写<span style="font-family: Arial, Helvetica, sans-serif;">dispatchMessage()来实现自己的具体操作</span>

            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();
        }
    }

可以看出,通过loop方法的调用,不断的换取消息,交给handler的dispatchMessage()来处理。至此将handler实例化到获取处理消息的代码分析完了,但是还没有分析handler消息发送过程。即handler实现异步处理是一个消息发送到接收处理闭环的过程,现在来看下消息发送过程。


    public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }

   //中间代码省略
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

    /**
     * Sends a Message containing only the what value.
     *  
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */
    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

    /**
     * Sends a Message containing only the what value, to be delivered
     * after the specified amount of time elapses.
     * @see #sendMessageDelayed(android.os.Message, long) 
     * 
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */
    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

    /**
     * Sends a Message containing only the what value, to be delivered 
     * at a specific time.
     * @see #sendMessageAtTime(android.os.Message, long)
     *  
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.
     */

    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }

    /**
     * Enqueue a message into the message queue after all pending messages
     * before (current time + delayMillis). You will receive it in
     * {@link #handleMessage}, in the thread attached to this handler.
     *  
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    /**
     * Enqueue a message into the message queue after all pending messages
     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
     * Time spent in deep sleep will add an additional delay to execution.
     * You will receive it in {@link #handleMessage}, in the thread attached
     * to this handler.
     * 
     * @param uptimeMillis The absolute time at which the message should be
     *         delivered, using the
     *         {@link android.os.SystemClock#uptimeMillis} time-base.
     *         
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

可以看到无论是post还是sendmessage的方式,最终都会调用到sendMessageAtTime,在这个方法中,又调用了enqueneMessage这个方法,他是将消息放入队列中,进行循环,具体实现这里不在往下分析,总之,消息最后还是会交由Looper来取出交由Handler处理。

/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

在Handler处理消息过程中,如果post的是Runable参数,则交由handlerCallback处理,如果是message类型,则判断是否处理过,如果没有,执行handleMessage来处理消息。





版权声明:本文为博主原创文章,未经博主允许不得转载。

Android事件处理方法总结-Handler消息处理

Android Handler消息处理:4个主要参与对象(Handler 消息发送接收处理类 + Message消息对象 + MessageQuene消息队列 + Looper:每个线程只拥有一个Lo...
  • yihuiworld
  • yihuiworld
  • 2015年06月03日 12:44
  • 4461

Android Handler消息处理机制详解

前言 从我们学习android开始,几乎每天都在和handler打交道.有了它,我们在子线程中处理好了耗时的操作,可以利用它来更新UI.它为我们在线程间的通信提供了很大的方便,而今天博客就来详细的介绍...
  • u011692041
  • u011692041
  • 2016年05月11日 10:48
  • 6969

Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38377229 ,本文出自【张鸿洋的博客】很多人面试肯定都被问到过,请问Andro...
  • lmj623565791
  • lmj623565791
  • 2014年08月07日 09:17
  • 194870

Android的消息处理机制--Looper,Handler

  • 2012年09月02日 22:42
  • 479KB
  • 下载

Android_Handler消息处理机制

  • 2015年12月07日 00:12
  • 1.18MB
  • 下载

Android多线程及异步任务消息处理机制 一 Handler的使用

  • 2014年08月26日 12:39
  • 3.21MB
  • 下载

android的消息处理机制(图+源码分析)——Looper,Handler,Message

作为一个大三的预备程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设计思想。android源码中包含了大量的设计模式,除此以外,android sdk还精心为我们设计了各种...
  • x1971481259
  • x1971481259
  • 2016年09月20日 13:47
  • 70

android的消息处理机制(图+源码分析)——Looper,Handler,Message

android的消息处理有三个核心类:Looper,Handler和Message。其实还有一个Message Queue(消息队列),但是MQ被封装到Looper里面了,我们不会直接与MQ打交道,因...
  • cxq_leelen
  • cxq_leelen
  • 2016年07月28日 19:29
  • 177

Android Handler 异步消息处理机制的妙用 创建强大的图片加载类

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38476887 ,本文出自【张鸿洋的博客】上一篇博客介绍了Android异步消息处...
  • lmj623565791
  • lmj623565791
  • 2014年08月11日 00:47
  • 59542

Android异步消息处理Handler

帮助博客: 郭霖:http://blog.csdn.net/guolin_blog/article/details/9991569 张鸿洋:http://blog.csdn.net/l...
  • Sorry957
  • Sorry957
  • 2017年12月04日 18:31
  • 45
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android消息处理之Handler
举报原因:
原因补充:

(最多只允许输入30个字)