Android中Handler的理解与总结

来源:互联网 发布:软件项目经理绩效考核 编辑:程序博客网 时间:2024/05/10 04:54

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
原创粉丝点击