Android系统中提供了两种实现多线程的方式,首先是我们Android编程中非常眼熟的Handler,然后是AsyncTask异步类,本章将讲解Handler方式实现多线程。在本章正式开始前,我觉得有必要说一下Android为什么需要多线程。

其实Android中的多线程主要是用来避免ANR(ApplicationNot Responding),手机比较卡的同学可能会经常遇到这种情况,手机界面卡住没有响应了,过了一段时间,Android系统弹出一个对话框,显示”ApplicationNot Responding”并且让用户选择”wait”or “close”. 为什么会出现这种状况呢?这还要从Android的系统机制说起。

Android系统中,一个程序第一次启动,Android会同时启动一个对应的主线程(MainThread),主线程主要负责处理UI相关的事件,所以主线程又叫做UI线程。在Android开发中必须遵循单线程模型的原则:UI操作并不是线程安全的,并且这些操作必须在UI线程中执行,这与普通的java程序不同。但是,无可避免的UI线程中的一些操作会很耗时,如网络连接。Android系统的机制除了单线程模型的特点,还要求Activiy的最长执行时间不能超过5s,BroadcastReceiver的最长执行时间不能超过10s,否则就会出现之前提到的ANR。正因为如此,Android中的多线程也就应运而生了。如果在新开的线程中需要对UI进行设定,就可能违反单线程模型,因此android采用一种复杂的MessageQueue机制保证线程间通信。

Google在设计Android的消息循环机制的时候是参考了Windows程序的消息循环机制的,因此Android的应用程序的消息循环机制也是由消息循环、消息发送和消息处理三部分构成的。下面是Android消息循环机制的示意图。

android 多并发接口 android 多个handler_Android

图一Android消息循环机制的示意图

要理解Android的消息循环机制需要把握好下面这四个核心类:

(1)   Looper, 消息循环器。它负责源源不断的依次从MessageQueue中取出消息,并将消息分发到指定的Handler对象进行处理。

(2)   MessageQueue, 消息队列。它是被封装在Looper中的,接受Handler发来的消息,按照FIFO规则执行,等待Looper的抽取。

(3)   Handler, 消息的发送者和处理者。 每个Handler在创建时都被绑定到一个Looper,它把消息发送到与它绑定的Looper的消息队列中。

(4)   Message, 消息类。它封装了消息的相关内容。包括消息ID,消息处理对象以及处理额数据等。由Message列队,由Handler处理。

完成UI线程与工作线程建立消息循环,需要以下几个步骤:

(1)   生成工作线程的Looper,通过调用Looper.prepare()方法来实现。

(2)   将Handler与工作线程的Looper绑定,通过在工作线程中创建Handler对象实现。

(3)   定义消息处理方法,通过重写Handler的handlerMessage()方法实现。

(4)   启动消息循环,通过调用Looper.loop()方法实现。

(5)   结束消息循环,通过调用Looper.quit()方法实现。

是不是还不能满足你的胃口,上面这些一条一条如政治书上面的条目,实在让人提不起兴趣。下面将通过对Looper类和Handler类的解读来完成对Android消息处理机制的深入理解,看一下Google的大牛们是如何完成对Android消息循环的设计的。

首先来看下Looper的源码,Looper是消息的维护者,下面将会看到如何通过prepare()创建一个Looper,调用loop()执行消息循环,以及quit()推出消息循环。

public class Looper {
    private static final String TAG = "Looper";
	
    //sThreadLocal负责存放当前线程的唯一一个Looper
    //ThreadLocal可以保证线程安全,关于ThreadLocal的深入理解,参照:
    //
    //如果没有调用prepare()方法,sThreadLocal.get()将会返回null
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    //Looper里面的消息队列
    final MessageQueue mQueue;
    //当前线程
    final Thread mThread;
    //Looper是否开启,该变量使用volatile作为修饰,表示该变量是把修改过的值放到共享内存中,
    //并且如果被线程访问又会从共享内存中重新读取该成员变量的值,这样保证多个线程总是访问到它的同一值
    volatile boolean mRun;
    //日志
    private Printer mLogging = null;
    //UI线程
    private static Looper mMainLooper = null;  // guarded by Looper.class

    //prepare()用来初始化工作线程的Looper(后面还会看到loop()和quit()分别用来开始执行和结束一个loop)
    //一个线程只能有一个Looper否则会抛出异常
    public static void prepare() {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }

    //UI线程的Looper创建,该方法由Android系统提供。
    //可以看到方法内部已经有了prepare()方法,所以在UI线程中我们看不到prepare()方法
    public static void prepareMainLooper() {
        prepare();
        setMainLooper(myLooper());
        myLooper().mQueue.mQuitAllowed = false;
    }

    private synchronized static void setMainLooper(Looper looper) {
        mMainLooper = looper;
    }

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

    //消息循环
    public static void loop() {
    	//获取当前Looper
        Looper me = myLooper();
        //当没有调用prepare()就直接调用loop()便会抛出异常
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //得到当前Looper的MessageQueue
        MessageQueue queue = me.mQueue;
        
        //确保当前线程属于当前进程,并记录下token。涉及到Android的权限检查,
        //有兴趣的同学可以看下这篇文章:
        //
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        //进入循环
        while (true) {
        	//从消息队列中取出消息,有可能会阻塞
            Message msg = queue.next(); // might block
            if (msg != null) {
            	//target指的就是Handler,后面解析Handler源码的时候会有说明是为什么
                if (msg.target == null) {
                	//当没有target也就是handler的时候,就退出消息
                    return;
                }

                long wallStart = 0;
                long threadStart = 0;

                //一个局部变量,为UI事件设置log记录
                Printer logging = me.mLogging;
                if (logging != null) {
                    logging.println(">>>>> Dispatching to " + msg.target + " " +
                            msg.callback + ": " + msg.what);
                    wallStart = SystemClock.currentTimeMicro();
                    threadStart = SystemClock.currentThreadTimeMicro();
                }
                //handler处理消息
                msg.target.dispatchMessage(msg);

                if (logging != null) {
                    long wallTime = SystemClock.currentTimeMicro() - wallStart;
                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;

                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
                    if (logging instanceof Profiler) {
                        ((Profiler) logging).profile(msg, wallStart, wallTime,
                                threadStart, threadTime);
                    }
                }

                //确保分发消息的时候,线程没有被销毁
                //涉及到Android的权限检查,有兴趣的同学可以看下这篇文章:
                //
                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);
                }
                //回收Message
                msg.recycle();
            }
        }
    }

    //返回线程相关Looper
    public static Looper myLooper() {
        return sThreadLocal.get();
    }

    //用来打印消息
    public void setMessageLogging(Printer printer) {
        mLogging = printer;
    }
    
    //返回和当前线程相关的MessageQueue,它必须是从一个有Looper的线程中被调用,
    //否则,将会抛出空指针异常
    public static MessageQueue myQueue() {
        return myLooper().mQueue;
    }
	
    //创建一个新的looper对象
    private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }
	
    //退出消息循环
    public void quit() {
        Message msg = Message.obtain();
        //往消息队列中加入一个空的msg,这就是为什么我们知道消息退出了
        mQueue.enqueueMessage(msg, 0);
    }

    /**
     * Return the Thread associated with this Looper.
     */
    public Thread getThread() {
        return mThread;
    }

    /** @hide */
    public MessageQueue getQueue() {
        return mQueue;
    }

    public void dump(Printer pw, String prefix) {
        pw = PrefixPrinter.create(pw, prefix);
        pw.println(this.toString());
        pw.println("mRun=" + mRun);
        pw.println("mThread=" + mThread);
        pw.println("mQueue=" + ((mQueue != null) ? mQueue : "(null"));
        if (mQueue != null) {
            synchronized (mQueue) {
                long now = SystemClock.uptimeMillis();
                Message msg = mQueue.mMessages;
                int n = 0;
                while (msg != null) {
                    pw.println("  Message " + n + ": " + msg.toString(now));
                    n++;
                    msg = msg.next;
                }
                pw.println("(Total messages: " + n + ")");
            }
        }
    }

    public String toString() {
        return "Looper{" + Integer.toHexString(System.identityHashCode(this)) + "}";
    }

    /**
     * @hide
     */
    public static interface Profiler {
        void profile(Message message, long wallStart, long wallTime,
                long threadStart, long threadTime);
    }
}

下面来看下handler的源码,通过上面的消息循环的机制图我们可以看到handler主要负责消息的发送(sendMessage)以及消息的处理(handleMessage

public class Handler {

    private static final boolean FIND_POTENTIAL_LEAKS = false;
    private static final String TAG = "Handler";

    public interface Callback {
        public boolean handleMessage(Message msg);
    }
    
    //该方法最终回调交给我们自己实现
    public void handleMessage(Message msg) {
    }
    
    //在Looper中message的target就是handler,target调用dispatchMessage()处理消息
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
        	//如果message设置了callback,处理callback
            handleCallback(msg);
        } else {
        	//如果handler本身设置了callback,执行callback
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //该方法需要我们覆写实现
            handleMessage(msg);
        }
    }

    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();
        //如果当前线程没有Looper,这是会抛出异常,显示没有调用prepare()
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //关键来了!直接把Looper的Queue赋给自己的Queue,于是实现了handler与Looper的关联
        mQueue = mLooper.mQueue;
        mCallback = null;
    }

    ....................

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

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

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

    //其它的发送消息的方法实际最后都是调用了该方法,下面解释了handler如何与Looper进行关联
    public boolean sendMessageAtTime(Message msg, long uptimeMillis)
    {
        boolean sent = false;
        MessageQueue queue = mQueue;
        if (queue != null) {
        	//这就是为什么我们前面说msg.target就是指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.      在子线程中必须加Looper.prepare(), 用来创建对应的Looper。而在UI线程中,已经有了prepare(), 所以不需要加prepare().

2.      一个线程只能对应一个Looper,通过ThreadLocal存放为一个的一个Looper保证线程安全。

3.      一个Looper可以对应多个handler,直接把Looper的Queue赋给handler的Queue,实现它们之间的关联。

4.      一个Looper对应着一个MessageQueue,并由它来维护。

5.      Handler中的handleMessage()回调方法,需要程序员进行覆写。