Android中Handler的理解与总结

android的异步处理消息机制Handler这个问题是老生常谈哪,这个要追溯到一个面试的场景了,面试官说,handler发送完消息后,什么时候触发循环,这个我说了,handler源码中有个looper,这个是用来循环取出handler发送到消息队列(messageQueue)中的消息,一旦Looper开启Looper.loop()就开启无限循环,直接取出MessageQueue中所有的消息,然后面试官不知道是他怎么理解的,我说的是looper.loop()就开启循环,他没说话,可能不在一个频道上抑或是我回答的不对?我感觉他也不是特别的理解吧,哎,有点坑哪,这面试真是醉了,什么样的面试官都会遇到,面试还真是运气加上实力,我觉得吧,可能还是缘分未到吧,但是我喜欢总结,我觉得自己要深刻的理解,现在我就去再去深入的看下这个Handler,下次再问到此类问题信手拈来,插一句,可能那个面试官他真的不是特别理解吧!

 首先,咱们理解几个概念,见名知意吧,下面的博客中会以口语化形式表述出来。

 Message(消息),MessageQueue(消息队列),Looper(循环,很重要),Handler(用来发送和处理消息)

1.Handler分析发送消息的过程

Handler mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
    }
};
上面那种写法咱们是咱们最常用的,new完后,重写handleMessage方法,里面的传递介质Message就是我们发送的消息,我们看看他的内部是如何处理的,直接点击Handler

/**
 * Default constructor associates this handler with the {@link Looper} for the
 * current thread.
 *
 * If this thread does not have a looper, this handler won't be able to receive messages
 * so an exception is thrown.
 */
public Handler() {
    this(null, false);
}
看到他的构造函数使用的这类里面的构造,传入参数是null 和 false,我们继续点击this这个函数

/**
 * Use the {@link Looper} for the current thread with the specified callback interface
 * and set whether the handler should be asynchronous.
 *
 * Handlers are synchronous by default unless this constructor is used to make
 * one that is strictly asynchronous.
 *
 * Asynchronous messages represent interrupts or events that do not require global ordering
 * with respect to synchronous messages.  Asynchronous messages are not subject to
 * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
 *
 * @param callback The callback interface in which to handle messages, or null.
 * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
 * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
 *
 * @hide
 */
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());
        }
    }

    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内部定义的如下所示:

/**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
 *
 * @param msg A {@link android.os.Message Message} object
 * @return True if no further handling is desired
 */
public interface Callback {
    public boolean handleMessage(Message msg);
}
其实也是最后调用handlerMessage(Message msg)这个方法,就像我们刚才使用的那种方式,我们可以这样理解,这个Handler有好几种的使用方式,可以传接口,也可以直接new出来,然后重写handlerMessage方法,几个入口吧。

第二个参数是一个boolean类型,这个消息是否是异步的,这里我们new出来的默认是false,也就是不是异步的消息,是同步的消息,异步的消息这里提前说下,异步消息就不能保证顺序了,因为这里面还有MessageQueue消息队列的概念,下面会继续说的。

ok,new完handler后,可以看到给mLooper 设置了与当前线程相关联的Looper对象,mQueue为当前looper对象里面的消息队列,而looper和messageQueue是在Looper对象实例化后相关联的,可以看下两者的关联代码

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
ok,上面讲的是new完Handler后的代码追踪,也就是在newHanlder后,获取到当前的looper对象并设置到Handler里面的成员变量mLooper,还有将Handler成员变量消息队列mQueue 设置为当前Looper对象所关联的消息队列mLooper.mQueue;

下面这个步骤就是handler发送消息了,追踪下代码

/**
 * 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);
}
不管你是sendMessage还是sendMessageDelayed最终代码都会执行到这个sendMessageAtTime方法中,可以看到第一个参数是Message我们的传递介质,消息载体,第二个就是时间,消息的绝对时间,然后接着追踪代码

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
在这里可以看到msg.target = this,可以很好的理解,即当前消息的目标,也就是发送消息的句柄是当前的对象也就是Handler,将其赋值,然后判断是否是异步的消息,如果是,设置为true,然后将这个消息入队返回true 或者false,表示消息进入队列是否成功

继续往下看

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
这是消息入队的代码,会先判断当前目标target是否为null,这个消息是否正在使用等最后返回true,表示消息入队成功。

 2.疑问:到这里我们可能要问了,这逻辑已经顺着下来了,handler什么时候去处理消息哪,现在只有入没有处理消息啊?

   ok,上述1的过程只是消息的发送过程,现在我们来看看消息的处理,我们不要忘记了Looper这个对象,先查看其源码,其中有这个方法

/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
public static void loop() {

当looper调用这个方法后会开启无限循环,循环从messageQueue中取出message,然后调用msg.target.dispatchMessage去处理消息,可以看下代码

try {
    msg.target.dispatchMessage(msg);
} finally {
    if (traceTag != 0) {
        Trace.traceEnd(traceTag);
    }
}
而target就是当前new的handler,我们看handler里面dispatchMessage的方法是如何处理的

/**
 * 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);
    }
}
看到上面的注释说明”在这里处理系统的消息“,然后我们惊喜的发现了callback,对,没错,就是在最初初始化handler的时候,传的callback参数,但是我们这个是null啊,对的,所有他执行了else,执行了handleMessage,然后这就是我们为什么重写handleMessage的原因,好了,但是callback的使用场景是什么

new Handler().post(new Runnable() {
    @Override
    public void run() {
       new TextView(TestActivity.this).setText("xxxxx");
    }
});
我们直接使用handler.post 发送了一个runnable,点击post后,可以看到执行的顺序和sendMessage是一样的

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}
不过是通过getPostMessage(r)获取了一个消息,而此时callback = r;
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

此时的callback不为空,那最后执行到这个dispatchMessage时,由于callback不是null,所以直接执行了runnable的run方法,不信,请看代码

private static void handleCallback(Message message) {
    message.callback.run();
}
整个流程走完了,但是回到最初的问题,面试官说,什么时候触发循环,因为我们已经知道必须调用looper.loop()方法才能触发无限循环,说这样也没错啊,但是我们new的时候并没有使用looper的loop方法啊,ok,问题就在这里,我们Activity在初始化的时候,系统已经帮我们做好了

Looper.prepareMainLooper();

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

if (sMainThreadHandler == null) {
    sMainThreadHandler = thread.getHandler();
}

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

// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
在ActivityThread这个类中,系统初始了mainLooper,所以new Handler后默认为mainLooper,最下面的那个Looper.loop(),系统已经帮助我们开启消息循环了,比如我们之前经常这样写

  new Thread(){
        public void run(){
            Looper.prepare();
            handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                }
            };
            Looper.loop();
        }
    }.start();
}
上述代码是在子线程中使用handler,这个时候要注意,因为已经切换了线程,不再是默认的UI主线程,所以looper也不再是main Looper,所以Looper.prepare是将当前子线程绑定到当前looper对象,最后一定要开启消息循环,这是最经典的写法和使用。

综上所述,可能我没有get到面试官的点吧,抑或是面试官在这个问题上也存在着疑问吧,不管怎么说吧,自己都要要求自己去理解,不能再知道表层了,与君共勉吧!


参考文章:

http://blog.csdn.net/lmj623565791/article/details/38377229


  

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值