Android应用中的消息循环由Looper和Handler配合完成,Looper类用于封装消息循环,类中有个MessageQueue消息队列;Handler类封装了消息投递和消息处理等功能。在Looper.java中有一个loop()方法,有个死循环用来处理消息,代码如下:

/**     * Run the message queue in this thread. Be sure to call     * {@link #quit()} to end the loop.     */    public static void loop() {        Looper me = myLooper();        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        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();                while (true) {            Message msg = queue.next(); // might block //            if (msg != null) {                if (msg.target == null) {                    // No target is a magic identifier for the quit message.                    return;                }                long wallStart = 0;                long threadStart = 0;                // 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);                    wallStart = SystemClock.currentTimeMicro();                    threadStart = SystemClock.currentThreadTimeMicro();                }                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);                    }                }                // 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.recycle();            }        }    }


通过查看MessageQueue类可以看出,消息队列是以链表形式保存的(在android.os.Message类中有个成员变量为Message next)。在loop()方法的死循环中通过queue.next()读取MessageQueue中的Message,由此也可以看出MessageQueue的next()及enqueueMessage()方法需要同步。    系统默认情况下只有主线程(即UI线程)绑定Looper对象,因此在主线程中可以直接创建Handler的实例(见ActivityThread类),但是在子线程中就不能直接new出Handler的实例了,因为子线程默认并没有Looper对象,此时会抛出RuntimeException异常(在Handler类构造函数中会抛出异常):
        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }    如果需要在子线程中使用Handler类,首先需要创建Looper类实例,这时可以通过Looper.prepare()和Looper.loop()函数来实现的。阅读Framework层源码发现,Android为我们提供了一个HandlerThread类,该类继承Thread类,并使用上面两个函数创建Looper对象。源码如下:

 /** * Handy class for starting a new thread that has a looper. The looper can then be  * used to create handler classes. Note that start() must still be called. */public class HandlerThread extends Thread {    int mPriority;    int mTid = -1;    Looper mLooper;    public HandlerThread(String name) {        super(name);        mPriority = Process.THREAD_PRIORITY_DEFAULT;    }        /**     * Constructs a HandlerThread.     * @param name     * @param priority The priority to run the thread at. The value supplied must be from      * {@link android.os.Process} and not from java.lang.Thread.     */    public HandlerThread(String name, int priority) {        super(name);        mPriority = priority;    }        /**     * Call back method that can be explicitly over ridden if needed to execute some     * setup before Looper loops.     */    protected void onLooperPrepared() {    }    public void run() {        mTid = Process.myTid();        Looper.prepare();        synchronized (this) {            mLooper = Looper.myLooper();            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();        mTid = -1;    }        /**     * This method returns the Looper associated with this thread. If this thread not been started     * or for any reason is isAlive() returns false, this method will return null. If this thread      * has been started, this method will block until the looper has been initialized.       * @return The looper.     */    public Looper getLooper() {        if (!isAlive()) {            return null;        }                // If the thread has been started, wait until the looper has been created.        synchronized (this) {            while (isAlive() && mLooper == null) {                try {                    wait();//Looper对象未创建好,等待                } catch (InterruptedException e) {                }            }        }        return mLooper;    }        /**     * Ask the currently running looper to quit.  If the thread has not     * been started or has finished (that is if {@link #getLooper} returns     * null), then false is returned.  Otherwise the looper is asked to     * quit and true is returned.     */    public boolean quit() {        Looper looper = getLooper();        if (looper != null) {            looper.quit();            return true;        }        return false;    }        /**     * Returns the identifier of this thread. See Process.myTid().     */    public int getThreadId() {        return mTid;    }}
  

在run()方法中通过Looper.prepare()获取Looper对象,而且通过线程的wait()和notifyAll()解决了getLooper()获取为空的问题。不管是主线程(一般是我们的UI线程)还是子线程,只要有Looper的线程,别的线程就可以向这个线程的消息队列中发送消息和计划任务,然后做相应的处理。

更多相关文章

  1. Android(安卓)xmpp开发 asmack获取离线在线添加好友消息 及 好友
  2. android欢迎界面的编程实现[手相评分-软件实例]
  3. 充电clientandroid电池(五):电池 充电IC(PM2301)驱动分析篇
  4. Android(安卓)消息处理机制: Handler 中 sendMessage()方法的几
  5. android 网络连接保活
  6. Android中的RxJava详解
  7. android部分介绍
  8. Android(安卓)Studio使用JDBC连接MySQL出现java.lang.Unsupporte
  9. Android简易聊天室软件(HTTP实现)

随机推荐

  1. 详述Entity Framework自定义分页效果实现
  2. 详解如何用WPF图形解锁控件ScreenUnLock
  3. ASP.NET中怎样用MVC5的MiniProfiler对MVC
  4. C++ 之 Asio 库
  5. C#中关于RabbitMQ应用的图文代码详解
  6. ASP.NET MVC中SignalR用法讲解
  7. C++函数与指针
  8. 关于ASP.NET如何利用AjaxPro完成前端跟后
  9. 介绍MVC、MVP和MVVM的区别与用法
  10. 学习asp.net的学习顺序与学习内容分享