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中的多线程之handler_第1张图片

图一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的深入理解,参照:    //http://www.cnblogs.com/dolphin0520/p/3920407.html    //如果没有调用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的权限检查,        //有兴趣的同学可以看下这篇文章:        //http://blog.csdn.net/windskier/article/details/6921672        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的权限检查,有兴趣的同学可以看下这篇文章:                //http://blog.csdn.net/windskier/article/details/6921672                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()回调方法,需要程序员进行覆写。


更多相关文章

  1. 《第一行代码--Android》读书笔记之多线程与服务
  2. Android异步机制一:使用Thread+Handler实现非UI线程更新UI界面
  3. Android主线程消息循环
  4. 下载Android Sdk源码方法
  5. android 多任务多线程断点下载
  6. [Android]Thread线程入门3--多线程
  7. Android 自定义属性时TypedArray的使用方法
  8. Android TV 智能电视/盒子 APP 开发焦点控制 两种方法实例
  9. android v7包 正常导入使用方法

随机推荐

  1. 手机淘宝Android客户端架构
  2. 深入讲解Android(安卓)MVP框架,附一个很屌
  3. 玩Android小程序v2.0,力争做最漂亮的玩And
  4. 使用CSS3 Media Query技术适配Android平
  5. Android轮播的实现与分析
  6. android开发中对于onLowMemory& onTrimMe
  7. 【转】Android导出jar library时资源reso
  8. Android(安卓)Binder实现浅析-Binder驱动
  9. Android中原始资源的使用
  10. 南青信息查询 for Android客户端