理解Handler、Looper、MessageQueue、Thread关系?二

1.线程间通讯机制


这一篇博文主要是和大家讲解一下线程间通讯机制的内部实现原理,即Handler、Message、MessageQueue、Looper、HandlerThread、AsyncTask类的实现以及之间的关系。如果还没有接触过Handler+Message+Runnable、HandlerThread、AsyncTask的朋友可以先看看基础篇:


【Android开发】线程间通讯机制(基础篇)——Handler、Runnable、HandlerThread、AsyncTask的使用


有时候,如果你能带着问题或者目标去探索新知识的话,这样的学习效率就高很多。所以我们先从最基础的实现方式(Handler+Message+Runnable)说起。


一、Handler+Message+Runnable内部解析

问题:我们在使用Handler类的时候,都知道有sendMessage(Message)等发送消息的功能和post(Runnable)发送任务的功能,然后还有能够处理接受到的Message的功能。这时候我就会提出这样的问题:

1、有发送、接受Message的功能,是不是sendMessage方法是直接调用handleMessage的重写方法里呢?

2、不是有按时间计划发送Message和Runnable吗?如果问题1成立的话,handleMessage可能会同时接受多个Message,但是此方法不是线程安全的(没有synchronized修饰),这样会出现问题了。

    

解决问题:如果对API有任何疑惑,最根本的方法就是查看源代码。

在看源代码之前,需要了解几个类:

Handler:负责发送Message和Runnable到MessageQueue中,然后依次处理MessageQueue里面的队列。

MessageQueue:消息队列。负责存放一个线程的Message和Runnable的集合。

Message:消息实体类。

Looper:消息循环器。负责把MessageQueue中的Message或者Runnable循环取出来,然后分发到Handler中。


四者的关系:一个线程可以有多个Handler实例,一个线程对应一个Looper,一个Looper也只对应一个MessageQueue,一个MessageQueue对应多个Message和Runnable。所以就形成了一对多的对应关系,一方:线程、Looper、MessageQueue;多方:Handler、Message。同时可以看出另一个一对一关系:一个Message实例对应一个Handler实例。


一个Handler实例都会与一个线程和消息队列捆绑在一起,当实例化Handler的时候,就已经完成这样的工作。源码如下:

Handler类

[java]  view plain copy
  1. /** 
  2.      * Default constructor associates this handler with the {@link Looper} for the 
  3.      * current thread. 
  4.      * 
  5.      * If this thread does not have a looper, this handler won't be able to receive messages 
  6.      * so an exception is thrown. 
  7.      */  
  8.     public Handler() {  
  9.         this(nullfalse);  
  10.     }  

[java]  view plain copy
  1. public Handler(Callback callback, boolean async) {  
  2.         if (FIND_POTENTIAL_LEAKS) {  
  3.             final Class<? extends Handler> klass = getClass();  
  4.             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
  5.                     (klass.getModifiers() & Modifier.STATIC) == 0) {  
  6.                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
  7.                     klass.getCanonicalName());  
  8.             }  
  9.         }  
  10.   
  11.         mLooper = Looper.myLooper();  
  12.         if (mLooper == null) {  
  13.             throw new RuntimeException(  
  14.                 "Can't create handler inside thread that has not called Looper.prepare()");  
  15.         }  
  16.         mQueue = mLooper.mQueue;  
  17.         mCallback = callback;  
  18.         mAsynchronous = async;  
  19.     }  

  可以从mLooper = Looper.myLooper()

mQueue = mLooper.mQueue;看出,实例化Handler就会绑定一个Looper实例,并且一个Looper实例包涵一个MessageQueue实例。

问题来了,为什么说一个线程对应一个Looper实例?我们通过Looper.myLooper()找原因:

Looper类

[java]  view plain copy
  1. // sThreadLocal.get() will return null unless you've called prepare().  
  2.    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();  

[java]  view plain copy
  1. /** 
  2.      * Return the Looper object associated with the current thread.  Returns 
  3.      * null if the calling thread is not associated with a Looper. 
  4.      */  
  5.     public static Looper myLooper() {  
  6.         return sThreadLocal.get();  
  7.     }  

ThreadLocal类

Implements a thread-local storage, that is, a variable for which each thread has its own value. All threads sharethe sameThreadLocal object, but each sees a different value when accessing it, and changes made by onethread do not affect the other threads. The implementation supportsnull values.


——实现一个线程本地的存储,就是说每个线程都会有自己的内存空间来存放线程自己的值。所有线程都共享一个ThreadLocal对象,但是不同的线程都会对应不同的value,而且单独修改不影响其他线程的value,并且支持null值。


所以说,每个线程都会存放一个独立的Looper实例,通过ThreadLocal.get()方法,就会获得当前线程的Looper的实例。


好了,接下来就要研究一下Handler发送Runnable,究竟怎么发送?

Handler类:

[java]  view plain copy
  1. public final boolean post(Runnable r)  
  2.     {  
  3.        return  sendMessageDelayed(getPostMessage(r), 0);  
  4.     }  

[java]  view plain copy
  1. private static Message getPostMessage(Runnable r) {  
  2.         Message m = Message.obtain();  
  3.         m.callback = r;  
  4.         return m;  
  5.     }  

可以看出,其实传入的Runnable对象都是封装到Message类中,看下Message是存放什么信息:

Message类:

[java]  view plain copy
  1. public final class Message implements Parcelable {    
  2.     public int what;    
  3.     public int arg1;    
  4.     public int arg2;    
  5.     public Object obj;    
  6.     public Messenger replyTo;    
  7.     long when;    
  8.     Bundle data;    
  9.     Handler target;         
  10.     Runnable callback;     
  11.     Message next;    
  12.     private static Object mPoolSync = new Object();    
  13.     private static Message mPool;    
  14.     private static int mPoolSize = 0;    
  15.     private static final int MAX_POOL_SIZE = 10;   

When: 向Handler发送Message生成的时间
Data: 在Bundler 对象上绑定要线程中传递的数据
Next: 当前Message 对一下个Message 的引用
Handler: 处理当前Message 的Handler对象.
mPool: 通过字面理解可能叫他Message池,但是通过分析应该叫有下一个Message引用的Message链更加适合.
其中Message.obtain(),通过源码分析就是获取断掉Message链关系的第一个Message.

       对于源码的解读,可以明确两点:

        1)Message.obtain()是通过从全局Message pool中读取一个Message,回收的时候也是将该Message 放入到pool中。

        2)Message中实现了Parcelable接口


所以接下来看下Handler如何发送Message:

Handler类

[java]  view plain copy
  1. /** 
  2.     * Enqueue a message into the message queue after all pending messages 
  3.     * before the absolute time (in milliseconds) <var>uptimeMillis</var>. 
  4.     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 
  5.     * You will receive it in {@link #handleMessage}, in the thread attached 
  6.     * to this handler. 
  7.     *  
  8.     * @param uptimeMillis The absolute time at which the message should be 
  9.     *         delivered, using the 
  10.     *         {@link android.os.SystemClock#uptimeMillis} time-base. 
  11.     *          
  12.     * @return Returns true if the message was successfully placed in to the  
  13.     *         message queue.  Returns false on failure, usually because the 
  14.     *         looper processing the message queue is exiting.  Note that a 
  15.     *         result of true does not mean the message will be processed -- if 
  16.     *         the looper is quit before the delivery time of the message 
  17.     *         occurs then the message will be dropped. 
  18.     */  
  19.    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
  20.        MessageQueue queue = mQueue;  
  21.        if (queue == null) {  
  22.            RuntimeException e = new RuntimeException(  
  23.                    this + " sendMessageAtTime() called with no mQueue");  
  24.            Log.w("Looper", e.getMessage(), e);  
  25.            return false;  
  26.        }  
  27.        return enqueueMessage(queue, msg, uptimeMillis);  
  28.    }  

[java]  view plain copy
  1. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
  2.        msg.target = this;  
  3.        if (mAsynchronous) {  
  4.            msg.setAsynchronous(true);  
  5.        }  
  6.        return queue.enqueueMessage(msg, uptimeMillis);  
  7.    }  



其实无论是按时间计划发送Message或者Runnable,最终是调用了sendMessageAtTime方法,里面核心执行的是enqueueMessage方法,就是调用了MessageQueue中的enqueueMessage方法,就是把消息Message加入到消息队列中。


这时候问题又来了,如果发送消息只是把消息加入到消息队列中,那谁来把消息分发到Handler中呢?

不妨我们看看Looper类:

[java]  view plain copy
  1. /** 
  2.      * Run the message queue in this thread. Be sure to call 
  3.      * {@link #quit()} to end the loop. 
  4.      */  
  5.     public static void loop() {  
  6.         final Looper me = myLooper();  
  7.         if (me == null) {  
  8.             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  
  9.         }  
  10.         final MessageQueue queue = me.mQueue;  
  11.   
  12.         // Make sure the identity of this thread is that of the local process,  
  13.         // and keep track of what that identity token actually is.  
  14.         Binder.clearCallingIdentity();  
  15.         final long ident = Binder.clearCallingIdentity();  
  16.   
  17.         for (;;) {  
  18.             Message msg = queue.next(); // might block  
  19.             if (msg == null) {  
  20.                 // No message indicates that the message queue is quitting.  
  21.                 return;  
  22.             }  
  23.   
  24.             // This must be in a local variable, in case a UI event sets the logger  
  25.             Printer logging = me.mLogging;  
  26.             if (logging != null) {  
  27.                 logging.println(">>>>> Dispatching to " + msg.target + " " +  
  28.                         msg.callback + ": " + msg.what);  
  29.             }  
  30.   
  31.             msg.target.<span style="color:#ff0000;"><strong>dispatchMessage</strong></span>(msg);  
  32.   
  33.             if (logging != null) {  
  34.                 logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);  
  35.             }  
  36.   
  37.             // Make sure that during the course of dispatching the  
  38.             // identity of the thread wasn't corrupted.  
  39.             final long newIdent = Binder.clearCallingIdentity();  
  40.             if (ident != newIdent) {  
  41.                 Log.wtf(TAG, "Thread identity changed from 0x"  
  42.                         + Long.toHexString(ident) + " to 0x"  
  43.                         + Long.toHexString(newIdent) + " while dispatching to "  
  44.                         + msg.target.getClass().getName() + " "  
  45.                         + msg.callback + " what=" + msg.what);  
  46.             }  
  47.   
  48.             msg.recycle();  
  49.         }  
  50.     }  
里面loop方法找到调用Handler的dispatchMessage的方法,我们再看看Handler的dispatchMessage:

[java]  view plain copy
  1. public void dispatchMessage(Message msg) {  
  2.        if (msg.callback != null) {  
  3.            handleCallback(msg);  
  4.        } else {  
  5.            if (mCallback != null) {  
  6.                if (mCallback.handleMessage(msg)) {  
  7.                    return;  
  8.                }  
  9.            }  
  10.            handleMessage(msg);  
  11.        }  
  12.    }  

dispatchMessage最终是回调了handleMessage。换句话说,Loop的loop()方法就是取得当前线程中的MessageQueue实例,然后不断循环消息分发到对应的Handler实例上。就是只要调用Looper.loop()方法,就可以执行消息分发。

小结:Handler、Message、MessageQueue、Looper的关系原理图:





整个机制实现原理流程:当应用程序运行的时候,会创建一个主线程(UI线程)ActivityThread,这个类里面有个main方法,就是java程序运行的最开始的入口

[java]  view plain copy
  1. public static void main(String[] args) {  
  2.         SamplingProfilerIntegration.start();  
  3.   
  4.         // CloseGuard defaults to true and can be quite spammy.  We  
  5.         // disable it here, but selectively enable it later (via  
  6.         // StrictMode) on debug builds, but using DropBox, not logs.  
  7.         CloseGuard.setEnabled(false);  
  8.   
  9.         Process.setArgV0("<pre-initialized>");  
  10.   
  11.         Looper.prepareMainLooper();  
  12.         if (sMainThreadHandler == null) {  
  13.             sMainThreadHandler = new Handler();  
  14.         }  
  15.   
  16.         ActivityThread thread = new ActivityThread();  
  17.         thread.attach(false);  
  18.   
  19.         if (false) {  
  20.             Looper.myLooper().setMessageLogging(new  
  21.                     LogPrinter(Log.DEBUG, "ActivityThread"));  
  22.         }  
  23.   
  24.         <span style="color:#ff0000;">Looper.loop();</span>  
  25.   
  26.         throw new RuntimeException("Main thread loop unexpectedly exited");  
  27.     }  

UI线程就开始就已经调用了loop消息分发,所以当在UI线程实例的Handler对象发送消息或者任务时,会把Message加入到MessageQueue消息队列中,然后分发到Handler的handleMessage方法里。


二、HandlerThread

其实上述就是线程间通讯机制的实现,而HandlerThread和AsyncTask只是对通讯机制进行进一步的封装,要理解也很简单:

HandlerThread类:

[java]  view plain copy
  1. public class HandlerThread extends Thread {  
  2.     int mPriority;  
  3.     int mTid = -1;  
  4.     Looper mLooper;  
  5.   
  6.     public HandlerThread(String name) {  
  7.         super(name);  
  8.         mPriority = Process.THREAD_PRIORITY_DEFAULT;  
  9.     }  
  10.       
  11.     /** 
  12.      * Constructs a HandlerThread. 
  13.      * @param name 
  14.      * @param priority The priority to run the thread at. The value supplied must be from  
  15.      * {@link android.os.Process} and not from java.lang.Thread. 
  16.      */  
  17.     public HandlerThread(String name, int priority) {  
  18.         super(name);  
  19.         mPriority = priority;  
  20.     }  
  21.       
  22.     /** 
  23.      * Call back method that can be explicitly overridden if needed to execute some 
  24.      * setup before Looper loops. 
  25.      */  
  26.     protected void onLooperPrepared() {  
  27.     }  
  28.   
  29.     public void run() {  
  30.         mTid = Process.myTid();  
  31.         <span style="color:#ff0000;">Looper.prepare();</span>  
  32.         synchronized (this) {  
  33.             mLooper = Looper.myLooper();  
  34.             notifyAll();  
  35.         }  
  36.         Process.setThreadPriority(mPriority);  
  37.         onLooperPrepared();  
  38.         <span style="color:#ff0000;">Looper.loop();</span>  
  39.         mTid = -1;  
  40.     }  
  41.       
  42.     /** 
  43.      * This method returns the Looper associated with this thread. If this thread not been started 
  44.      * or for any reason is isAlive() returns false, this method will return null. If this thread  
  45.      * has been started, this method will block until the looper has been initialized.   
  46.      * @return The looper. 
  47.      */  
  48.     public Looper getLooper() {  
  49.         if (!isAlive()) {  
  50.             return null;  
  51.         }  
  52.           
  53.         // If the thread has been started, wait until the looper has been created.  
  54.         synchronized (this) {  
  55.             while (isAlive() && mLooper == null) {  
  56.                 try {  
  57.                     wait();  
  58.                 } catch (InterruptedException e) {  
  59.                 }  
  60.             }  
  61.         }  
  62.         return mLooper;  
  63.     }  
  64.       
  65.     /** 
  66.      * Ask the currently running looper to quit.  If the thread has not 
  67.      * been started or has finished (that is if {@link #getLooper} returns 
  68.      * null), then false is returned.  Otherwise the looper is asked to 
  69.      * quit and true is returned. 
  70.      */  
  71.     public boolean quit() {  
  72.         Looper looper = getLooper();  
  73.         if (looper != null) {  
  74.             looper.quit();  
  75.             return true;  
  76.         }  
  77.         return false;  
  78.     }  
  79.       
  80.     /** 
  81.      * Returns the identifier of this thread. See Process.myTid(). 
  82.      */  
  83.     public int getThreadId() {  
  84.         return mTid;  
  85.     }  
  86. }  
 可以看得出,HandlerThread继承了Thread,从run()方法可以看出,HandlerThread要嗲用start()方法,才能实例化HandlerThread的Looper对象,和消息分发功能。

所以使用HandlerThread,必须先运行HandlerThread,才能取出对应的Looper对象,然后使用Handler(Looper)构造方法实例Handler,这样Handler的handleMessage方法就是子线程执行了。


三、AsyncTask


AsyncTask现在是android应用开发最常用的工具类,这个类面向调用者是轻量型的,但是对于系统性能来说是重量型的。这个类很强大,使用者很方便就能使用,只需要在对应的方法实现特定的功能即可。就是因为AsyncTask的强大封装,所以说不是轻量型的,先看下源代码吧:

[java]  view plain copy
  1. public abstract class AsyncTask<Params, Progress, Result> {  
  2.     private static final String LOG_TAG = "AsyncTask";  
  3.   
  4.     private static final int CORE_POOL_SIZE = 5;  
  5.     private static final int MAXIMUM_POOL_SIZE = 128;  
  6.     private static final int KEEP_ALIVE = 1;  
  7.   
  8.     private static final ThreadFactory sThreadFactory = new ThreadFactory() {  
  9.         private final AtomicInteger mCount = new AtomicInteger(1);  
  10.   
  11.         public Thread newThread(Runnable r) {  
  12.             return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());  
  13.         }  
  14.     };  
  15.   
  16.     private static final BlockingQueue<Runnable> sPoolWorkQueue =  
  17.             new LinkedBlockingQueue<Runnable>(10);  
  18.   
  19.     /** 
  20.      * An {@link Executor} that can be used to execute tasks in parallel. 
  21.      */  
  22.     public static final Executor THREAD_POOL_EXECUTOR  
  23.             = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,  
  24.                     TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);  
  25.   
  26.     /** 
  27.      * An {@link Executor} that executes tasks one at a time in serial 
  28.      * order.  This serialization is global to a particular process. 
  29.      */  
  30.     public static final Executor SERIAL_EXECUTOR = new SerialExecutor();  
  31.   
  32.     private static final int MESSAGE_POST_RESULT = 0x1;  
  33.     private static final int MESSAGE_POST_PROGRESS = 0x2;  
  34.   
  35.     private static final InternalHandler sHandler = new InternalHandler();  
  36.   
  37.     private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;  
  38.     private final WorkerRunnable<Params, Result> mWorker;  
  39.     private final FutureTask<Result> mFuture;  
  40.   
  41.     private volatile Status mStatus = Status.PENDING;  
  42.       
  43.     private final AtomicBoolean mCancelled = new AtomicBoolean();  
  44.     private final AtomicBoolean mTaskInvoked = new AtomicBoolean();  
  45.   
  46.     private static class SerialExecutor implements Executor {  
  47.         final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();  
  48.         Runnable mActive;  
  49.   
  50.         public synchronized void execute(final Runnable r) {  
  51.             mTasks.offer(new Runnable() {  
  52.                 public void run() {  
  53.                     try {  
  54.                         r.run();  
  55.                     } finally {  
  56.                         scheduleNext();  
  57.                     }  
  58.                 }  
  59.             });  
  60.             if (mActive == null) {  
  61.                 scheduleNext();  
  62.             }  
  63.         }  
  64.   
  65.         protected synchronized void scheduleNext() {  
  66.             if ((mActive = mTasks.poll()) != null) {  
  67.                 THREAD_POOL_EXECUTOR.execute(mActive);  
  68.             }  
  69.         }  
  70.     }  
  71.   
  72.     /** 
  73.      * Indicates the current status of the task. Each status will be set only once 
  74.      * during the lifetime of a task. 
  75.      */  
  76.     public enum Status {  
  77.         /** 
  78.          * Indicates that the task has not been executed yet. 
  79.          */  
  80.         PENDING,  
  81.         /** 
  82.          * Indicates that the task is running. 
  83.          */  
  84.         RUNNING,  
  85.         /** 
  86.          * Indicates that {@link AsyncTask#onPostExecute} has finished. 
  87.          */  
  88.         FINISHED,  
  89.     }  
  90.   
  91.     /** @hide Used to force static handler to be created. */  
  92.     public static void init() {  
  93.         sHandler.getLooper();  
  94.     }  
  95.   
  96.     /** @hide */  
  97.     public static void setDefaultExecutor(Executor exec) {  
  98.         sDefaultExecutor = exec;  
  99.     }  
  100.   
  101.     /** 
  102.      * Creates a new asynchronous task. This constructor must be invoked on the UI thread. 
  103.      */  
  104.     public AsyncTask() {  
  105.         mWorker = new WorkerRunnable<Params, Result>() {  
  106.             public Result call() throws Exception {  
  107.                 mTaskInvoked.set(true);  
  108.   
  109.                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
  110.                 //noinspection unchecked  
  111.                 return postResult(doInBackground(mParams));  
  112.             }  
  113.         };  
  114.   
  115.         mFuture = new FutureTask<Result>(mWorker) {  
  116.             @Override  
  117.             protected void done() {  
  118.                 try {  
  119.                     postResultIfNotInvoked(get());  
  120.                 } catch (InterruptedException e) {  
  121.                     android.util.Log.w(LOG_TAG, e);  
  122.                 } catch (ExecutionException e) {  
  123.                     throw new RuntimeException("An error occured while executing doInBackground()",  
  124.                             e.getCause());  
  125.                 } catch (CancellationException e) {  
  126.                     postResultIfNotInvoked(null);  
  127.                 }  
  128.             }  
  129.         };  
  130.     }  
  131.   
  132.     private void postResultIfNotInvoked(Result result) {  
  133.         final boolean wasTaskInvoked = mTaskInvoked.get();  
  134.         if (!wasTaskInvoked) {  
  135.             postResult(result);  
  136.         }  
  137.     }  
  138.   
  139.     private Result postResult(Result result) {  
  140.         @SuppressWarnings("unchecked")  
  141.         Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,  
  142.                 new AsyncTaskResult<Result>(this, result));  
  143.         message.sendToTarget();  
  144.         return result;  
  145.     }  
  146.   
  147.       
  148.     public final Status getStatus() {  
  149.         return mStatus;  
  150.     }  
  151.   
  152.       
  153.     protected abstract Result doInBackground(Params... params);  
  154.   
  155.      
  156.     protected void onPreExecute() {  
  157.     }  
  158.   
  159.       
  160.     @SuppressWarnings({"UnusedDeclaration"})  
  161.     protected void onPostExecute(Result result) {  
  162.     }  
  163.   
  164.       
  165.     @SuppressWarnings({"UnusedDeclaration"})  
  166.     protected void onProgressUpdate(Progress... values) {  
  167.     }  
  168.   
  169.      
  170.     @SuppressWarnings({"UnusedParameters"})  
  171.     protected void onCancelled(Result result) {  
  172.         onCancelled();  
  173.     }      
  174.       
  175.       
  176.     protected void onCancelled() {  
  177.     }  
  178.   
  179.       
  180.     public final boolean isCancelled() {  
  181.         return mCancelled.get();  
  182.     }  
  183.   
  184.       
  185.     public final boolean cancel(boolean mayInterruptIfRunning) {  
  186.         mCancelled.set(true);  
  187.         return mFuture.cancel(mayInterruptIfRunning);  
  188.     }  
  189.   
  190.       
  191.     public final Result get() throws InterruptedException, ExecutionException {  
  192.         return mFuture.get();  
  193.     }  
  194.   
  195.       
  196.     public final Result get(long timeout, TimeUnit unit) throws InterruptedException,  
  197.             ExecutionException, TimeoutException {  
  198.         return mFuture.get(timeout, unit);  
  199.     }  
  200.   
  201.       
  202.     public final AsyncTask<Params, Progress, Result> execute(Params... params) {  
  203.         return executeOnExecutor(sDefaultExecutor, params);  
  204.     }  
  205.   
  206.      
  207.     public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,  
  208.             Params... params) {  
  209.         if (mStatus != Status.PENDING) {  
  210.             switch (mStatus) {  
  211.                 case RUNNING:  
  212.                     throw new IllegalStateException("Cannot execute task:"  
  213.                             + " the task is already running.");  
  214.                 case FINISHED:  
  215.                     throw new IllegalStateException("Cannot execute task:"  
  216.                             + " the task has already been executed "  
  217.                             + "(a task can be executed only once)");  
  218.             }  
  219.         }  
  220.   
  221.         mStatus = Status.RUNNING;  
  222.   
  223.         onPreExecute();  
  224.   
  225.         mWorker.mParams = params;  
  226.         exec.execute(mFuture);  
  227.   
  228.         return this;  
  229.     }  
  230.   
  231.       
  232.     public static void execute(Runnable runnable) {  
  233.         sDefaultExecutor.execute(runnable);  
  234.     }  
  235.   
  236.       
  237.     protected final void publishProgress(Progress... values) {  
  238.         if (!isCancelled()) {  
  239.             sHandler.obtainMessage(MESSAGE_POST_PROGRESS,  
  240.                     new AsyncTaskResult<Progress>(this, values)).sendToTarget();  
  241.         }  
  242.     }  
  243.   
  244.     private void finish(Result result) {  
  245.         if (isCancelled()) {  
  246.             onCancelled(result);  
  247.         } else {  
  248.             onPostExecute(result);  
  249.         }  
  250.         mStatus = Status.FINISHED;  
  251.     }  
  252.   
  253.     private static class InternalHandler extends Handler {  
  254.         @SuppressWarnings({"unchecked""RawUseOfParameterizedType"})  
  255.         @Override  
  256.         public void handleMessage(Message msg) {  
  257.             AsyncTaskResult result = (AsyncTaskResult) msg.obj;  
  258.             switch (msg.what) {  
  259.                 case MESSAGE_POST_RESULT:  
  260.                     // There is only one result  
  261.                     result.mTask.finish(result.mData[0]);  
  262.                     break;  
  263.                 case MESSAGE_POST_PROGRESS:  
  264.                     result.mTask.onProgressUpdate(result.mData);  
  265.                     break;  
  266.             }  
  267.         }  
  268.     }  
  269.   
  270.     private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {  
  271.         Params[] mParams;  
  272.     }  
  273.   
  274.     @SuppressWarnings({"RawUseOfParameterizedType"})  
  275.     private static class AsyncTaskResult<Data> {  
  276.         final AsyncTask mTask;  
  277.         final Data[] mData;  
  278.   
  279.         AsyncTaskResult(AsyncTask task, Data... data) {  
  280.             mTask = task;  
  281.             mData = data;  
  282.         }  
  283.     }  
  284. }  

要理解这个工具类,主要是理解这几个成员对象:

private static final InternalHandler sHandler = new InternalHandler();


    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;


    private final WorkerRunnable<Params, Result> mWorker;


    private final FutureTask<Result> mFuture;


分析:sHandler

消息的发送者和处理者

 sDefualtExecutor

线程执行者。实际上就是一个线程池。

 mWorker

WorkerRunnable实现了Callable接口,就是有返回值的线程任务。

 mFuture

FutureTask是对Callable执行的一个管理类,能够获得线程执行返回的结果,和取消执行等操作。我们再深入一下FutureTask,其中的done()方法是回调方法:

[java]  view plain copy
  1. /** 
  2.   * Removes and signals all waiting threads, invokes done(), and 
  3.   * nulls out callable. 
  4.   */  
  5.  private void finishCompletion() {  
  6.      // assert state > COMPLETING;  
  7.      for (WaitNode q; (q = waiters) != null;) {  
  8.          if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {  
  9.              for (;;) {  
  10.                  Thread t = q.thread;  
  11.                  if (t != null) {  
  12.                      q.thread = null;  
  13.                      LockSupport.unpark(t);  
  14.                  }  
  15.                  WaitNode next = q.next;  
  16.                  if (next == null)  
  17.                      break;  
  18.                  q.next = null// unlink to help gc  
  19.                  q = next;  
  20.              }  
  21.              break;  
  22.          }  
  23.      }  
  24.   
  25.     <span style="color:#cc0000;"> done();</span>  
  26.   
  27.      callable = null;        // to reduce footprint  
  28.  }  

只要线程移除或者挂起(取消)的时候,就会调用done()方法,然后在AsyncTask类中的mTask实现了done()方法,最后回调onCancelled()方法。


具体的流程原理是这样的:

1、当第一次AsyncTask在UI线程实例化,其实是实例化Handler,同时UI线程的Looper和MessageQueue绑定在sHandler对象中,之后再去实例话AsyncTask不会在初始化Handler,因为sHandler是类变量。

2、当执行execute方法的时候,实际上是调用线程池的execute方法运行线程

3、callable线程执行体就是调用了doInBackground(mParams)方法,然后以返回结果result当参数,又调用postResult(Result result),实际上就是利用sHandler来发送result到UI线程的MessageQueue中,最后sHandler接受到result后,回调onPostExecute方法。

4、如果主动调用publishProgress(Progress... values)方法,就会利用sHandler把value发送到UI线程的MessageQueue中,然后sHandler接收到value后,回调onProgressUpdate(Progress... values)方法。


注意:sHandler和mDefaultExecutor是类变量

  mWorker和mFuture是实例变量

所以,无论进程中生成多少个AysncTask对象,sHandler和mDefaultExecutor都是同一个,只是任务不同而已。


四、总结

由于我放上去的源代码删除了一些注释,如果还不能了解清楚的话,可以自行去源代码上观看。线程间通讯机制的核心就是Handler+Message+Looper+MessageQueue,只要理解这个四者的实现原理,再多的封装好的工具类也难理解。所以,必须记住一点:android应用开发多线程是必不可少的,所以我们必须遵循UI线程模式开发,就是所有耗时不能在UI线程执行,操作UI必须在UI线程中执行。



2.Android开发之消息处理机制(二)——消息循环

/*

 *  Android开发之消息处理机制(二)——消息循环

 *  北京Android俱乐部群:167839253  

 *  Created on: 2011-9-1

 *  Author: blueeagle

 *  Email: liujiaxiang@gmail.com

 */

 

       先介绍一下如何在Android应用程序中使用后台线程和UI线程。

创建Android友好的后台线程时,最灵活的方式就是创建Handler子类的一个实例。每个Activity仅需要一个Handler对象,而且不需要手动注册他。

       后台线程可以与Handler通讯,Handler将在Activity的UI线程上执行自己所有的工作。这一点非常重要。因为UI的更改,只能发生在Activity的UI线程上。

       有两种与Handler通信的方式:消息和Runnable对象。

       关于消息:

       要向Handler发送一个Message,首先调用obtainMessage()从池中获取Message对象。obtainMessage()对象有许多特点,允许创建空的Message对象或填充了消息标示符和参数的对象。需要的Handler处理过程越复杂,就越需要将数据放在Message中,以帮助Handler区分不同的事件。

       然后可以通过消息队列将Message发送给Handler,此时需要使用sendMessage…()系列方法中的一个方法。

       sendMessage();立即将消息放在队列中。

       sendMessageAtFrontOfQueue();立即将消息放在队列中,并将其放在消息队列的最前面,这样该消息就会具有比所有其他消息更高的优先级。

       sendMessageAtTime();在规定的时间将消息放在队列中,这个时间用ms表示,基于系统正常工作时间。(SystemClock.uptimeMillis())

       sendMessageDelayed();在一段延迟之后将消息放在队列中,延迟用ms表示。

       要处理这些消息,Handler需要实现handleMessage(),将使用出现在消息队列中的每个消息来调用handleMessage()。此处Handler可以根据需要更新UI。但是,它仍然应该迅速完成此工作,因为在它完成之前,其他UI工作会暂停。

       关于Runnable :

       如果不愿意使用Message对象,也可以将Runnable对象传递给Handler,Handler将在ActivityUI线程上运行这些Runnable对象。Handler提供了一组post…()方法来传入Runnable对象供最终处理。

       对Android的消息循环机制的理解,可以仿照Windows消息循环的机制进行。

每个Handler都会和一个线程和线程的message queue关联起来,此时你可以传递messages 和 runnable对象到message queue中。后面可以从message queue中拿出该对象并且执行。Handler, Message queue这两个对象之间的交互,就涉及到了Looper这个东西。

关于Handler,Looper,Message Queue三者之间的关系,如下图所示:

Handler有很多构造函数

Handler在无参数的构造方法中调用Looper.myLooper()方法,里面就是从当前线程里面获取一个Looper的同时一并初始化MessageQueue,并且从中得到looper的MessageQueue。可以看出Handler就是Looper和MessageQueue的管理者和调度者。

       其中最重要的是sendMessageAtTime方法,当你往Handler中发送Message消息的时候,从代码看出他自己并不去处理Message,而是交给了MessageQueue,由queue.enqueueMessage来处理。

       Looper代码中有一个prepare()方法,通过ThreadLocal实现一个线程只有一个Looper。

Handler的消息发送

Handler是一个核心,负责message的创建,获得,处理。Handler的sendMessage()方法最终其实就是调用了queue.enqueueMessage(msg, uptimeMillis);把消息放入message queue中。Looper通过Looper.loop()检测到有消息并将消息广播后,Handler又负责接收到此消息并调用handleMessage进行处理接下来的事情。Message的创建一般都是通过如下代码建立的,把Handler传进去。

     public final Message obtainMessage()

               {

                 return Message.obtain(this);

       }

这种工作方式如下图所示:

Message在里面是一个链表的结构。在这个方法中,会首先去MessagePool(消息回收站)去找Message,如果有被回收的Message,则会将这个Message取出来进行再利用。如果没有被回收的,这时系统才会真正new一个Message对象出来当然MessagePool不是无限大的,它最多只能保存十条回收的消息,多出来的就直接删除了。

至此,我们看到,一个Message经由Handler创建、发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler进行处理。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。

在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象(系统已经帮我们创建了);在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。在创建Handler之前,为该线程准备好一个Looper(Looper.prepare),然后让这个Looper跑起来(Looper.loop),抽取Message,这样,Handler才能正常工作。

因此,Handler处理消息总是在创建Handler的线程里运行。

下面根据上述理论知识,来举几个例子:

例1:

       在UI线程中调用Handler的Post方法。代码如下:

[java]  view plain copy
  1. /* 
  2.  *  Android开发之消息处理机制(二)——消息循环 
  3.  *  MessageCircle.java   
  4.  *  Created on: 2011-9-2 
  5.  *  Author: blueeagle 
  6.  *  Email: liujiaxiang@gmail.com 
  7.  */  
  8. package blueeagle.com;  
  9.   
  10. import android.app.Activity;  
  11. import android.os.Bundle;  
  12. import android.os.Handler;  
  13.   
  14. public class MessageCircle extends Activity {  
  15.     /** Called when the activity is first created. */  
  16.     private Handler myHandler = new Handler();  
  17.     private Runnable myRunnable = new Runnable(){  
  18.         @Override  
  19.         public void run(){  
  20.             try{  
  21.                 Thread.sleep(1000);  
  22.             }  
  23.             catch(InterruptedException e){  
  24.                 e.printStackTrace();  
  25.             }  
  26.             System.out.println("Current Runnable Thread ID:"+Thread.currentThread().getId());  
  27.         }  
  28.     };  
  29.     @Override  
  30.     public void onCreate(Bundle savedInstanceState) {  
  31.         super.onCreate(savedInstanceState);  
  32.         setContentView(R.layout.main);          
  33.         System.out.println("Current Activity Thread ID:"+Thread.currentThread().getId());  
  34.         myHandler.post(myRunnable);  
  35.     }      
  36. }  


 

程序运行结果如下图:

在这个程序中,我们New了一个没有参数的Handler对象myHandler,这个myHandler自动与当前运行程序相关联,也就是说,这个myHandler将与当前运行的线程使用同一个消息队列,并且可以处理该队列中的消息。

在程序代码中,这个myHandler向消息队列中post了一个myRunnable对象。在myRunnable的run方法中,打印当前线程的ID。由结果得知,我们New出来的这个myHandler是把消息或者Runnable对象送到当前的线程中的。这里我们没有调用线程的start()函数,因此也就不会去创建一个新的线程。而是在原有线程的内部,直接调用run()方法。因此输出的ID是相同的。

那么如何创建新的线程呢?在Android开发之消息处理机制(一)中已经知道如何去创建一个新的线程,这里继续举一个例子来进行比较说明。

例2:

首先需要创建一个线程,这个线程可以是自己创建的线程,也可以是HandlerThread,这个线程需要继承于Thread类或者实现Runnable接口。其次需要有一个Handler,这个Handler可以是Handler也可以继承于Handler并且需要有一个有Looper参数的构造函数。然后就可以进行消息的分发执行了。

具体示例代码如下:

[java]  view plain copy
  1. /* 
  2.  *  Android开发之消息处理机制(二)——消息循环 
  3.  *  MessageCircle.java   
  4.  *  Created on: 2011-9-2 
  5.  *  Author: blueeagle 
  6.  *  Email: liujiaxiang@gmail.com 
  7.  */  
  8.   
  9. package blueeagle.com;  
  10.   
  11. import android.app.Activity;  
  12. import android.os.Bundle;  
  13. import android.os.Handler;  
  14. import android.os.HandlerThread;  
  15. import android.os.Looper;  
  16. import android.os.Message;  
  17. import android.widget.TextView;  
  18.   
  19. public class MessageCircle extends Activity {  
  20.     public class MyOwnThread extends Thread{  
  21.         int sleepSpan = 2000;//休眠时间  
  22.         boolean flag;// 线程执行标志位  
  23.         //----------------------------------//  
  24.         //构造方法,初始化类的主要成员变量  
  25.         public MyOwnThread(){  
  26.             this.flag = true;  
  27.         }  
  28.         //----------------------------------//  
  29.         //方法,线程执行方法  
  30.         @Override  
  31.         public void run(){  
  32.             TextView myTextView = (TextView)findViewById(R.id.mytextview);  
  33.             Looper.prepare();  
  34.             int i = 1;  
  35.             while(flag){  
  36.                 try{  
  37.                     Thread.sleep(sleepSpan);//休眠一段时间  
  38.                     System.out.println("Current MyOwnThread Thread ID: "+Thread.currentThread().getId());  
  39.                     myTextView.setText(i);  
  40.                     i++;  
  41.                 }  
  42.                 catch(Exception e){  
  43.                     e.printStackTrace();//捕获异常并打印  
  44.                 }  
  45.             }                 
  46.             Looper.loop();  
  47.         }  
  48.     }  
  49.     public class MyHandler extends Handler{  
  50.         public MyHandler(){}  
  51.         public MyHandler(Looper looper){  
  52.             super(looper);  
  53.         }  
  54.         @Override  
  55.         public void handleMessage(Message msg){  
  56.             System.out.println("Current MyHandle Thread ID: "+Thread.currentThread().getId());  
  57.             TextView myTextView = (TextView)findViewById(R.id.mytextview);  
  58.             int i = 1;  
  59.             while(true){  
  60.                 try{  
  61.                     Thread.sleep(1000);//休眠一段时间  
  62.                     System.out.println("Current MyHandle Thread ID: "+Thread.currentThread().getId());  
  63.                     myTextView.setText("i");  
  64.                     i++;  
  65.                 }  
  66.                 catch(Exception e){  
  67.                     e.printStackTrace();//捕获异常并打印  
  68.                 }  
  69.             }         
  70.         }  
  71.     }  
  72.     /** Called when the activity is first created. */  
  73.     private MyHandler myHandler = null;  
  74.     @Override  
  75.     public void onCreate(Bundle savedInstanceState) {  
  76.         super.onCreate(savedInstanceState);  
  77.         setContentView(R.layout.main);          
  78.         System.out.println("Current Activity Thread ID:"+Thread.currentThread().getId());  
  79.         //myHandler.post(myRunnable);  
  80.         HandlerThread myThread = new HandlerThread("myThread");//生成一个HandlerThread对象,使用Looper来处理消息队列。  
  81.         myThread.start();//启动这个线程  
  82.         myHandler = new MyHandler(myThread.getLooper());//将一个线程绑定到myHandler这个对象上。  
  83.         Message msg = myHandler.obtainMessage();//从myHandler这个对象中获取消息  
  84.         msg.sendToTarget();//将msg对象发送给目标的Handler  
  85.           
  86.         //下面制造一个自己的线程  
  87.         MyOwnThread myOwnThread = new MyOwnThread();  
  88.         myOwnThread.start();  
  89.     }      
  90. }  


 

关于线程更新UI的方法,在(一)中已经说过。下面利用一个示例将消息循环过程进行展示,进而实现音乐播放,UI线程中更新歌词的例子来说明消息处理机制。例子较简单,没有实现歌词同步等内容。只是为了更深刻的理解线程运行情况。

按照上述理论:代码如下:

[java]  view plain copy
  1. /* 
  2.  *  Android开发之消息处理机制(二)——消息循环 
  3.  *  MusicPlayer.java   
  4.  *  Created on: 2011-9-3 
  5.  *  Author: blueeagle 
  6.  *  Email: liujiaxiang@gmail.com 
  7.  */  
  8.   
  9. package blueeagle.com;  
  10.   
  11. import android.app.Activity;  
  12. import android.media.MediaPlayer;  
  13. import android.os.Bundle;  
  14. import android.os.Handler;  
  15. import android.os.Looper;  
  16. import android.os.Message;  
  17. import android.view.View;  
  18. import android.view.View.OnClickListener;  
  19. import android.widget.Button;  
  20. import android.widget.TextView;  
  21.   
  22. public class MusicPlayer extends Activity {  
  23.     /** Called when the activity is first created. */  
  24.     Button myButton;  
  25.     TextView myTextView;  
  26.     private UIUpdateThread myUpdateThread = new UIUpdateThread(); //定义一个自己的UI更新的线程类  
  27.     MyHandler mHandler = new MyHandler();//定义自己的一个Handler类  
  28.     @Override  
  29.     public void onCreate(Bundle savedInstanceState) {  
  30.         super.onCreate(savedInstanceState);  
  31.         setContentView(R.layout.main);  
  32.         myButton = (Button)findViewById(R.id.myButton);  
  33.         myTextView = (TextView)findViewById(R.id.myTextView);  
  34.         myButton.setOnClickListener(new OnClickListener(){  
  35.             @Override  
  36.             public void onClick(View v) {  
  37.                 // TODO Auto-generated method stub   
  38.                 System.out.println("主线程运行ID:"+Thread.currentThread().getId());  
  39.                 new Thread(myUpdateThread).start();//起一个自己定义的线程  
  40.             }             
  41.         });  
  42.     }             
  43.     class MyHandler extends Handler{//继承Handler类时,必须重写handleMessage方法   
  44.         public MyHandler(){  
  45.               
  46.         }  
  47.         public MyHandler(Looper l){  
  48.             super(l);  
  49.             }  
  50.         @Override  
  51.         public void handleMessage(Message msg) {//执行接收到的通知,此时执行的顺序是按照队列进行,即先进先出   
  52.             myTextView.setText(msg.toString());  
  53.             System.out.println("Current Handler Thread ID:"+Thread.currentThread().getId());  
  54.             }   
  55.         }//该线程将会在单独的线程中运行  
  56.       
  57. class UIUpdateThread implements Runnable {    
  58. int i=1;  
  59.         public void run() {    
  60.             while (i<11) {    
  61.                 Message msg = mHandler.obtainMessage();  
  62.                 mHandler.sendMessage(msg);  
  63.                 System.out.println("新线程运行ID:"+Thread.currentThread().getId());  
  64.                 i++;  
  65.                 try {    
  66.                     Thread.sleep(4000);    
  67.                 } catch (InterruptedException e) {    
  68.                     // TODO Auto-generated catch block     
  69.                     e.printStackTrace();    
  70.                 }    
  71.             }    
  72.         }    
  73.     }  
  74. }  

关于简单的音乐播放的源码如下:

[java]  view plain copy
  1. /* 
  2.  *  Android开发之消息处理机制(二)——消息循环 
  3.  *  MusicPlayer.java   
  4.  *  Created on: 2011-9-3 
  5.  *  Author: blueeagle 
  6.  *  Email: liujiaxiang@gmail.com 
  7.  */  
  8.   
  9. package blueeagle.com;  
  10.   
  11. import android.app.Activity;  
  12. import android.media.MediaPlayer;  
  13. import android.os.Bundle;  
  14. import android.os.Handler;  
  15. import android.os.Looper;  
  16. import android.os.Message;  
  17. import android.view.View;  
  18. import android.view.View.OnClickListener;  
  19. import android.widget.Button;  
  20. import android.widget.TextView;  
  21.   
  22. public class MusicPlayer extends Activity {  
  23.     /** Called when the activity is first created. */  
  24.     private MediaPlayer mp;  
  25.     Button myButton;  
  26.     TextView myTextView;  
  27.     private UIUpdateThread myUpdateThread = new UIUpdateThread(); //定义一个自己的UI更新的线程类  
  28.     MyHandler mHandler = new MyHandler();//定义自己的一个Handler类  
  29.     @Override  
  30.     public void onCreate(Bundle savedInstanceState) {  
  31.         super.onCreate(savedInstanceState);  
  32.         setContentView(R.layout.main);  
  33.         myButton = (Button)findViewById(R.id.myButton);  
  34.         myTextView = (TextView)findViewById(R.id.myTextView);  
  35.         myButton.setOnClickListener(new OnClickListener(){  
  36.             @Override  
  37.             public void onClick(View v) {  
  38.                 // TODO Auto-generated method stub  
  39.                 mp = MediaPlayer.create(MusicPlayer.this, R.raw.yinweiaiqing);  
  40.                 mp.start();  
  41.                 System.out.println("主线程运行ID:"+Thread.currentThread().getId());  
  42.                 new Thread(myUpdateThread).start();  
  43.   
  44.             }             
  45.         });  
  46.     }             
  47.     class MyHandler extends Handler{//继承Handler类时,必须重写handleMessage方法   
  48.         public MyHandler(){  
  49.         }  
  50.         public MyHandler(Looper l){  
  51.             super(l);  
  52.             }  
  53.         @Override  
  54.         public void handleMessage(Message msg) {//执行接收到的通知,此时执行的顺序是按照队列进行,即先进先出   
  55.             myTextView.setText(msg.obj.toString());  
  56.             System.out.println("Current Handler Thread ID:"+Thread.currentThread().getId());  
  57.             }   
  58.         }//该线程将会在单独的线程中运行  
  59.     class UIUpdateThread implements Runnable {    
  60.         int i = 0;  
  61.         String myString[] = {  
  62.                 "这是一个实时播放的线程操作... ...",  
  63.                 "[00:08.79]《因为爱情》",  
  64.                 "[00:19.46]E 给你一张过去的CD",  
  65.                 "[00:28.68]听听那时我们的爱情",  
  66.                 "[00:34.12]有时会突然忘了",  
  67.                 "[00:37.48]我还在爱著你",  
  68.                 "[00:44.98]F 再唱不出那样的歌曲",  
  69.                 "[00:50.48]听到都会红著脸躲避",  
  70.                 "[00:55.83]虽然会经常忘了",  
  71.                 "[00:59.33]我依然爱著你",  
  72.                 "[01:05.49]F 因为爱情 不会轻易悲伤",  
  73.                 "[01:05.49]F 因为爱情 不会轻易悲伤",  
  74.                 "[01:12.09]E 所以一切都是幸福的模样",  
  75.                 "[01:17.24]F 因为爱情 简单的生长",  
  76.                 "[01:22.24]E 依然随时可以为你疯狂",  
  77.                 "[01:27.21]F 因为爱情 怎麼会有沧桑",  
  78.                 "[01:34.30]E 所以我们还是年轻的模样",  
  79.                 "[01:38.90]F 因为爱情 在那个地方",  
  80.                 "[01:44.32]E 依然还有人在那里游荡",  
  81.                 "[01:48.91]E&F 人来人往",  
  82.                 "[02:11.57]F 再唱不出那样的歌曲",  
  83.                 "[02:17.70]听到都会红著脸躲避",  
  84.                 "[02:23.14]虽然会经常忘了",  
  85.                 "[02:26.26]E&F 我依然爱著你",  
  86.                 "[02:32.60]F 因为爱情 不会轻易悲伤",  
  87.                 "[02:39.22]E 所以一切都是幸福的模样",  
  88.                 "[02:44.98]F 因为爱情 简单的生长",  
  89.                 "[02:49.36]E 依然随时可以为你疯狂",  
  90.                 "[02:54.38]F 因为爱情 怎麼会有沧桑",  
  91.                 "[03:00.94]E 所以我们还是年轻的模样",  
  92.                 "[03:06.04]F 因为爱情 在那个地方",  
  93.                 "[03:11.63]E 依然还有人在那里游荡",  
  94.                 "[03:17.04]E&F 人来人往",  
  95.                 "[03:21.98]E 给你一张过去的CD",  
  96.                 "[03:28.58]听听那时我们的爱情",  
  97.                 "[03:33.48]F 有时会突然忘了",  
  98.                 "[03:36.94]E&F 我还在爱著你"};  
  99.         public void run() {    
  100.             while (mp.isPlaying()) {    
  101.                 Message msg = mHandler.obtainMessage(111, myString[i]);  
  102.                 mHandler.sendMessage(msg);  
  103.                 System.out.println("新线程运行ID:"+Thread.currentThread().getId());  
  104.                 try {    
  105.                     Thread.sleep(4000);    
  106.                     i++;  
  107.                     if(i == myString.length){  
  108.                         i=myString.length-1;  
  109.                     }   
  110.                 } catch (InterruptedException e) {    
  111.                     // TODO Auto-generated catch block     
  112.                     e.printStackTrace();    
  113.                 }    
  114.             }    
  115.         }    
  116.     }  
  117. }  

综上,基本了解了Android下的关于线程,消息循环的一些概念,还需要深入了解Looper如何运用在程序中等。


3.Handler、Looper、MessageQueue、Thread实例

一、几个关键概念

1、MessageQueue:是一种数据结构,见名知义,就是一个消息队列,存放消息的地方。每一个线程最多只可以拥有一个MessageQueue数据结构。
创建一个线程的时候,并不会自动创建其MessageQueue。通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一
个默认的Looper对象,而Looper对象的创建,将自动创建一个Message Queue。其他非主线程,不会自动创建Looper,要需要的时候,通过调
用prepare函数来实现。

2、Message:消息对象,Message Queue中的存放的对象。一个Message Queue中包含多个Message。
Message实例对象的取得,通常使用Message类里的静态方法obtain(),该方法有多个重载版本可供选择;它的创建并不一定是直接创建一个新的实例,
而是先从Message Pool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果Message Pool中没有可用的Message实例,
则才用给定的参数创建一个Message对象。调用removeMessages()时,将Message从Message Queue中删除,同时放入到Message Pool中。除了上面这
种方式,也可以通过Handler对象的obtainMessage()获取一个Message实例。

3、Looper:
是MessageQueue的管理者。每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。同时每一个Looper对象
和一个线程关联。通过调用Looper.myLooper()可以获得当前线程的Looper对象
创建一个Looper对象时,会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能
接受Message。如需要接受,自己定义一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了。
Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理。处理完成后,调用Message.recycle()将其放入Message Pool中。

4、Handler:
消息的处理者,handler负责将需要传递的信息封装成Message,通过调用handler对象的obtainMessage()来实现;
将消息传递给Looper,这是通过handler对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。
当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法
对其进行处理。

二、线程之间的消息如何进行传递

1、主线程给自己发送Message

package test.message;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    
    private Button btnTest;
    private TextView textView;
    
    private Handler handler;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);
        
        btnTest.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                
                Looper looper = Looper.getMainLooper(); //主线程的Looper对象
                //这里以主线程的Looper对象创建了handler,
                //所以,这个handler发送的Message会被传递给主线程的MessageQueue。
                handler = new MyHandler(looper);
                handler.removeMessages(0);
                //构建Message对象
                //第一个参数:是自己指定的message代号,方便在handler选择性地接收
                //第二三个参数没有什么意义
                //第四个参数需要封装的对象
                Message msg = handler.obtainMessage(1,1,1,"主线程发消息了");
                
                handler.sendMessage(msg); //发送消息
                
            }
        });
    }
    
    class MyHandler extends Handler{
        
        public MyHandler(Looper looper){
            super(looper);
        }
        
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText("我是主线程的Handler,收到了消息:"+(String)msg.obj);
        }
    }
}

2、其他线程给主线程发送Message

package test.message;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    
    private Button btnTest;
    private TextView textView;
    
    private Handler handler;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);
        
        btnTest.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                
                //可以看出这里启动了一个线程来操作消息的封装和发送的工作
                //这样原来主线程的发送就变成了其他线程的发送,简单吧?呵呵
                new MyThread().start();    
            }
        });
    }
    
    class MyHandler extends Handler{
        
        public MyHandler(Looper looper){
            super(looper);
        }
        
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText("我是主线程的Handler,收到了消息:"+(String)msg.obj);
        }
    }
    
    //加了一个线程类
    class MyThread extends Thread{
        
        public void run(){
            Looper looper = Looper.getMainLooper(); //主线程的Looper对象
            //这里以主线程的Looper对象创建了handler,
            //所以,这个handler发送的Message会被传递给主线程的MessageQueue。
            handler = new MyHandler(looper);

            //构建Message对象
            //第一个参数:是自己指定的message代号,方便在handler选择性地接收
            //第二三个参数没有什么意义
            //第四个参数需要封装的对象
            Message msg = handler.obtainMessage(1,1,1,"其他线程发消息了");
            
            handler.sendMessage(msg); //发送消息            
        }
    }
}

3、主线程给其他线程发送Message

package test.message;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    
    private Button btnTest;
    private TextView textView;
    
    private Handler handler;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);
        
        
        //启动线程
        new MyThread().start();    
        
        btnTest.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                //这里handler的实例化在线程中
                //线程启动的时候就已经实例化了
                Message msg = handler.obtainMessage(1,1,1,"主线程发送的消息");
                handler.sendMessage(msg);
            }
        });
    }
    
    class MyHandler extends Handler{
        
        public MyHandler(Looper looper){
            super(looper);
        }
        
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText("我是主线程的Handler,收到了消息:"+(String)msg.obj);
        }
    }
    
    class MyThread extends Thread{
        
        public void run(){
            Looper.prepare(); //创建该线程的Looper对象,用于接收消息
            
            //注意了:这里的handler是定义在主线程中的哦,呵呵,
            //前面看到直接使用了handler对象,是不是在找,在什么地方实例化的呢?
            //现在看到了吧???呵呵,开始的时候实例化不了,因为该线程的Looper对象
            //还不存在呢。现在可以实例化了
            //这里Looper.myLooper()获得的就是该线程的Looper对象了
            handler = new ThreadHandler(Looper.myLooper());
            
            //这个方法,有疑惑吗?
            //其实就是一个循环,循环从MessageQueue中取消息。
            //不经常去看看,你怎么知道你有新消息呢???
            Looper.loop(); 

        }
        
        //定义线程类中的消息处理类
        class ThreadHandler extends Handler{
            
            public ThreadHandler(Looper looper){
                super(looper);
            }
            
            public void handleMessage(Message msg){
                //这里对该线程中的MessageQueue中的Message进行处理
                //这里我们再返回给主线程一个消息
                handler = new MyHandler(Looper.getMainLooper());
                
                Message msg2 = handler.obtainMessage(1,1,1,"子线程收到:"+(String)msg.obj);
                
                handler.sendMessage(msg2);
            }
        }
    }
}

4、其他线程给自己发送Message 

package test.message;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    
    private Button btnTest;
    private TextView textView;
    
    private Handler handler;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        btnTest = (Button)this.findViewById(R.id.btn_01);
        textView = (TextView)this.findViewById(R.id.view_01);
        
        
        btnTest.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View arg0) {
                //启动线程
                new MyThread().start();    
            }
        });
    }
    
    class MyHandler extends Handler{
        
        public MyHandler(Looper looper){
            super(looper);
        }
        
        public void handleMessage(Message msg){
            super.handleMessage(msg);
            textView.setText((String)msg.obj);
        }
    }    
    
    class MyThread extends Thread{
        
        public void run(){
            Looper.prepare(); //创建该线程的Looper对象
            //这里Looper.myLooper()获得的就是该线程的Looper对象了
            handler = new ThreadHandler(Looper.myLooper());
            Message msg = handler.obtainMessage(1,1,1,"我自己");
            handler.sendMessage(msg);
            
            Looper.loop(); 

        }
        
        //定义线程类中的消息处理类
        class ThreadHandler extends Handler{
            
            public ThreadHandler(Looper looper){
                super(looper);
            }
            
            public void handleMessage(Message msg){
                //这里对该线程中的MessageQueue中的Message进行处理
                //这里我们再返回给主线程一个消息
                //加入判断看看是不是该线程自己发的信息
                if(msg.what == 1 && msg.obj.equals("我自己")){
                    
                    handler = new MyHandler(Looper.getMainLooper());
                    
                    Message msg2 = handler.obtainMessage(1,1,1,"禀告主线程:我收到了自己发给自己的Message");
                    
                    handler.sendMessage(msg2);                
                }

            }
        }
    }
}

附注:
上面四个例子的布局文件是同一个文件main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  android:id="@+id/view_01"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
    
<Button android:id="@+id/btn_01" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="测试消息" />
</LinearLayout>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值