Android异步消息处理源码解析

概述

Android异步事件处理有很多方式,常用的有Handler的send(message)系列方法,post(runnable)系列方法,view.post(runnable)方法,runOnUiThread方法,AsyncTask以及EventBus。前面几种都是基于Handler机制,AsyncTask基于handler和线程池的封装,EventBus是基于发布者和订阅者的库,主要可以代替handler,intent,broadcastReceiver在Fragment,Activity,Service,线程之间传递消息,优点是开销小,代码更优雅,最重要的是将发送者和接收者解耦。
我们主要来看下Handler机制。

Handler机制

提到Handler就会涉及到MessageQueue和Looper。
Messagequeue并不是队列,而是单链表(便于插入和删除),就和ActivityThread,ApplicationThread和ThreadLocal不是线程一样(前者是UI线程的一个类,中间的实际上是一个binder,后面的是为了在不同的线程中保存数据副本)。Looper是每个MessageQueue的管家(ThreadLocal类型,每个线程都有自己的looper),它会无限循环的查找是否有新消息,没有就一直阻塞在那里,有就取出来交给handler处理。
MessageQueue 主要有两个方法enqueueMessage()和next()

boolean enqueueMessage(Message msg, long when) {
...}
 Message next() {
 ...}

enqueueMessage方法主要是单链表的插入操作,next方法是一个无限循环的方法,有就反回该Message并移除,没有就阻塞在那里。
每个线程要异步通信都只能有一个looper,没有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));
    }

有looper在创建会抛出异常,prepare()即为当前线程创造looper,此外还有两个方法


   public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

prepareMainLooper()会在ActivityThread的main方法中被调用,
主要是为UI线程创建Looper(getMainLooper方法可以在任何地方获取主线成的Looper),除此之外还会创建activitythread实例,并开启消息循环.

public static void main(String[] args) {

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

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
}

Looper还提供了退出方法,quit()和quitSafely();前者会让looper直接退出,后者会设定一个退出标记,等消息队列的所有消息处理完后再推出,类似于intentservice退出。

接着我们看消息循环方法:

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

loop()方法是一个死循环,只有当消息队列设定退出标记时它的next方法返回null时,这个时候会跳出循环。looper取出消息后把message分发给对应的handler,在相应的线程中处理事件。

接着我们来看Handler类,Looper类从MessageQueue中取出message交给hanlder来处理,在loop()中调用handler的dispatchMwssage方法;

 msg.target.dispatchMessage(msg);

msg.target即为对应的handler;我们来看看handler的dispatchMessage方法:

  public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

同时handler的post系列(runnable)方法也是通过send系列(message)方法实现的,把runnable对象包装成message对象,最终还是会调用handler的dispatchMessage方法

public final boolean post(Runnable r)
    {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
 private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

当message的callback(runnable)不为null时在对应handler所在线程执行runnable的run()。

  private static void handleCallback(Message message) {
        message.callback.run();
    }
/**
 * 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);
}

并且我们可以通过new Handler(callback)来创建handler对象(当我们不想通过handler的匿名内部类并重写handlerMessage方法时,可以通过callback接口来实现),当message的callback为null时,会判断handler对应的callback是否为null,不为null执行callback的handleMessage方法,否则执行handler的handleMessage方法。

view的post方法

该系列也是调用handler的post系列方法来完成

    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }
        // Assume that post will succeed later
        ViewRootImpl.getRunQueue().post(action);
        return true;
    }

runOnUiThread()

当前线程为主线成,执行runnable的run(),否则调用handler的post系列方法

public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值