Android消息处理-源码分析篇

AndroidLooper和Handler分析

 

第一次接触android应用程序(这里指的是JAVA层的UI程序,也难怪了,Google放出的API就只支持JAVA应用程序了),很难搞明白内部是如何实现的。但是,从原理上分析,应该是有一个消息循环,一个消息队列,然后主线程不断得从消息队列中取得消息并处理之。

然而,google封装得太厉害了,所以一时半会还是搞不清楚到底是怎么做的。本文将分析android内的looper,这个是用来封装消息循环和消息队列的一个类,handler其实可以看做是一个工具类,用来向消息队列中插入消息的。好比是Windows API的SendMessage中的HANDLE,这个handle是窗口句柄。

1.  //Looper类分析  
2.  //没找到合适的分析代码的办法,只能这么来了。每个重要行的上面都会加上注释  
3.  //功能方面的代码会在代码前加上一段分析  
4.  public class Looper {  
5.     //static变量,判断是否打印调试信息。  
6.      private static final boolean DEBUG = false;  
7.      private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;  
8.    
9.      // sThreadLocal.get() will return null unless you've called prepare().  
10.  //线程本地存储功能的封装,TLS,thread local storage,什么意思呢?因为存储要么在栈上,例如函数内定义的内部变量。要么在堆上,例如new或者malloc出来的东西  
11.  //但是现在的系统比如Linux和windows都提供了线程本地存储空间,也就是这个存储空间是和线程相关的,一个线程内有一个内部存储空间,这样的话我把线程相关的东西就存储到  
12.  //这个线程的TLS中,就不用放在堆上而进行同步操作了。  
13.      private static final ThreadLocal sThreadLocal = new ThreadLocal();  
14.  //消息队列,MessageQueue,看名字就知道是个queue..  
15.      final MessageQueue mQueue;  
16.      volatile boolean mRun;  
17.  //和本looper相关的那个线程,初始化为null  
18.      Thread mThread;  
19.      private Printer mLogging = null;  
20.  //static变量,代表一个UI Process(也可能是service吧,这里默认就是UI)的主线程  
21.      private static Looper mMainLooper = null;  
22.        
23.       /** Initialize the current thread as a looper. 
24.        * This gives you a chance to create handlers that then reference 
25.        * this looper, before actually starting the loop. Be sure to call 
26.        * {@link #loop()} after calling this method, and end it by calling 
27.        * {@link #quit()}. 
28.        */  
29.  //往TLS中设上这个Looper对象的,如果这个线程已经设过了looper的话就会报错  
30.  //这说明,一个线程只能设一个looper  
31.      public static final void prepare() {  
32.          if (sThreadLocal.get() != null) {  
33.              throw new RuntimeException("Only one Looper may be created per thread");  
34.          }  
35.          sThreadLocal.set(new Looper());  
36.      }  
37.        
38.      /** Initialize the current thread as a looper, marking it as an application's main  
39.       *  looper. The main looper for your application is created by the Android environment, 
40.       *  so you should never need to call this function yourself. 
41.       * {@link #prepare()} 
42.       */  
43.   //由framework设置的UI程序的主消息循环,注意,这个主消息循环是不会主动退出的  
44.  //      
45.      public static final void prepareMainLooper() {  
46.          prepare();  
47.          setMainLooper(myLooper());  
48.  //判断主消息循环是否能退出....  
49.  //通过quit函数向looper发出退出申请  
50.          if (Process.supportsProcesses()) {  
51.              myLooper().mQueue.mQuitAllowed = false;  
52.          }  
53.      }  
54.    
55.      private synchronized static void setMainLooper(Looper looper) {  
56.          mMainLooper = looper;  
57.      }  
58.        
59.      /** Returns the application's main looper, which lives in the main thread of the application. 
60.       */  
61.      public synchronized static final Looper getMainLooper() {  
62.          return mMainLooper;  
63.      }  
64.    
65.      /** 
66.       *  Run the message queue in this thread. Be sure to call 
67.       * {@link #quit()} to end the loop. 
68.       */  
69.  //消息循环,整个程序就在这里while了。  
70.  //这个是static函数喔!  
71.      public static final void loop() {  
72.          Looper me = myLooper();//从该线程中取出对应的looper对象  
73.          MessageQueue queue = me.mQueue;//取消息队列对象...  
74.          while (true) {  
75.              Message msg = queue.next(); // might block取消息队列中的一个待处理消息..  
76.              //if (!me.mRun) {//是否需要退出?mRun是个volatile变量,跨线程同步的,应该是有地方设置它。  
77.              //    break;  
78.              //}  
79.              if (msg != null) {  
80.                  if (msg.target == null) {  
81.                      // No target is a magic identifier for the quit message.  
82.                      return;  
83.                  }  
84.                  if (me.mLogging!= null) me.mLogging.println(  
85.                          ">>>>> Dispatching to " + msg.target + " "  
86.                          + msg.callback + ": " + msg.what  
87.                          );  
88.                  msg.target.dispatchMessage(msg);  
89.                  if (me.mLogging!= null) me.mLogging.println(  
90.                          "<<<<< Finished to    " + msg.target + " "  
91.                          + msg.callback);  
92.                  msg.recycle();  
93.              }  
94.          }  
95.      }  
96.    
97.      /** 
98.       * Return the Looper object associated with the current thread.  Returns 
99.       * null if the calling thread is not associated with a Looper. 
100.     */  
101.//返回和线程相关的looper  
102.    public static final Looper myLooper() {  
103.        return (Looper)sThreadLocal.get();  
104.    }  
105.  
106.    /** 
107.     * Control logging of messages as they are processed by this Looper.  If 
108.     * enabled, a log message will be written to <var>printer</var>  
109.     * at the beginning and ending of each message dispatch, identifying the 
110.     * target Handler and message contents. 
111.     *  
112.     * @param printer A Printer object that will receive log messages, or 
113.     * null to disable message logging. 
114.     */  
115.//设置调试输出对象,looper循环的时候会打印相关信息,用来调试用最好了。  
116.    public void setMessageLogging(Printer printer) {  
117.        mLogging = printer;  
118.    }  
119.      
120.    /** 
121.     * Return the {@link MessageQueue} object associated with the current 
122.     * thread.  This must be called from a thread running a Looper, or a 
123.     * NullPointerException will be thrown. 
124.     */  
125.    public static final MessageQueue myQueue() {  
126.        return myLooper().mQueue;  
127.    }  
128.//创建一个新的looper对象,  
129.//内部分配一个消息队列,设置mRun为true  
130.    private Looper() {  
131.        mQueue = new MessageQueue();  
132.        mRun = true;  
133.        mThread = Thread.currentThread();  
134.    }  
135.  
136.    public void quit() {  
137.        Message msg = Message.obtain();  
138.        // NOTE: By enqueueing directly into the message queue, the  
139.        // message is left with a null target.  This is how we know it is  
140.        // a quit message.  
141.        mQueue.enqueueMessage(msg, 0);  
142.    }  
143.  
144.    /** 
145.     * Return the Thread associated with this Looper. 
146.     */  
147.    public Thread getThread() {  
148.        return mThread;  
149.    }  
150.    //后面就简单了,打印,异常定义等。  
151.    public void dump(Printer pw, String prefix) {  
152.        pw.println(prefix + this);  
153.        pw.println(prefix + "mRun=" + mRun);  
154.        pw.println(prefix + "mThread=" + mThread);  
155.        pw.println(prefix + "mQueue=" + ((mQueue != null) ? mQueue : "(null"));  
156.        if (mQueue != null) {  
157.            synchronized (mQueue) {  
158.                Message msg = mQueue.mMessages;  
159.                int n = 0;  
160.                while (msg != null) {  
161.                    pw.println(prefix + "  Message " + n + ": " + msg);  
162.                    n++;  
163.                    msg = msg.next;  
164.                }  
165.                pw.println(prefix + "(Total messages: " + n + ")");  
166.            }  
167.        }  
168.    }  
169.  
170.    public String toString() {  
171.        return "Looper{"  
172.            + Integer.toHexString(System.identityHashCode(this))  
173.            + "}";  
174.    }  
175.  
176.    static class HandlerException extends Exception {  
177.  
178.        HandlerException(Message message, Throwable cause) {  
179.            super(createMessage(cause), cause);  
180.        }  
181.  
182.        static String createMessage(Throwable cause) {  
183.            String causeMsg = cause.getMessage();  
184.            if (causeMsg == null) {  
185.                causeMsg = cause.toString();  
186.            }  
187.            return causeMsg;  
188.        }  
189.    }  
190.}  


那怎么往这个消息队列中发送消息呢??调用looper的static函数myQueue可以获得消息队列,这样你就可用自己往里边插入消息了。不过这种方法比较麻烦,这个时候handler类就发挥作用了。先来看看handler的代码,就明白了。


1.  class Handler{  
2.  ..........  
3.  //handler默认构造函数  
4.  public Handler() {  
5.  //这个if是干嘛用的暂时还不明白,涉及到java的深层次的内容了应该  
6.          if (FIND_POTENTIAL_LEAKS) {  
7.              final Class<? extends Handler> klass = getClass();  
8.              if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
9.                      (klass.getModifiers() & Modifier.STATIC) == 0) {  
10.                  Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
11.                      klass.getCanonicalName());  
12.              }  
13.          }  
14.  //获取本线程的looper对象  
15.  //如果本线程还没有设置looper,这回抛异常  
16.          mLooper = Looper.myLooper();  
17.          if (mLooper == null) {  
18.              throw new RuntimeException(  
19.                  "Can't create handler inside thread that has not called Looper.prepare()");  
20.          }  
21.  //无耻啊,直接把looper的queue和自己的queue搞成一个了  
22.  //这样的话,我通过handler的封装机制加消息的话,就相当于直接加到了looper的消息队列中去了  
23.          mQueue = mLooper.mQueue;  
24.          mCallback = null;  
25.      }  
26.  //还有好几种构造函数,一个是带callback的,一个是带looper的  
27.  //由外部设置looper  
28.      public Handler(Looper looper) {  
29.          mLooper = looper;  
30.          mQueue = looper.mQueue;  
31.          mCallback = null;  
32.      }  
33.  // 带callback的,一个handler可以设置一个callback。如果有callback的话,  
34.  //凡是发到通过这个handler发送的消息,都有callback处理,相当于一个总的集中处理  
35.  //待会看dispatchMessage的时候再分析  
36.  public Handler(Looper looper, Callback callback) {  
37.          mLooper = looper;  
38.          mQueue = looper.mQueue;  
39.          mCallback = callback;  
40.      }  
41.  //  
42.  //通过handler发送消息  
43.  //调用了内部的一个sendMessageDelayed  
44.  public final boolean sendMessage(Message msg)  
45.      {  
46.          return sendMessageDelayed(msg, 0);  
47.      }  
48.  //FT,又封装了一层,这回是调用sendMessageAtTime了  
49.  //因为延时时间是基于当前调用时间的,所以需要获得绝对时间传递给sendMessageAtTime  
50.  public final boolean sendMessageDelayed(Message msg, long delayMillis)  
51.      {  
52.          if (delayMillis < 0) {  
53.              delayMillis = 0;  
54.          }  
55.          return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
56.      }  
57.    
58.    
59.  public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
60.      {  
61.          boolean sent = false;  
62.          MessageQueue queue = mQueue;  
63.          if (queue != null) {  
64.  //把消息的target设置为自己,然后加入到消息队列中  
65.  //对于队列这种数据结构来说,操作比较简单了  
66.              msg.target = this;  
67.              sent = queue.enqueueMessage(msg, uptimeMillis);  
68.          }  
69.          else {  
70.              RuntimeException e = new RuntimeException(  
71.                  this + " sendMessageAtTime() called with no mQueue");  
72.              Log.w("Looper", e.getMessage(), e);  
73.          }  
74.          return sent;  
75.      }  
76.  //还记得looper中的那个消息循环处理吗  
77.  //从消息队列中得到一个消息后,会调用它的target的dispatchMesage函数  
78.  //message的target已经设置为handler了,所以  
79.  //最后会转到handler的msg处理上来  
80.  //这里有个处理流程的问题  
81.  public void dispatchMessage(Message msg) {  
82.  //如果msg本身设置了callback,则直接交给这个callback处理了  
83.          if (msg.callback != null) {  
84.              handleCallback(msg);  
85.          } else {  
86.  //如果该handler的callback有的话,则交给这个callback处理了---相当于集中处理  
87.            if (mCallback != null) {  
88.                  if (mCallback.handleMessage(msg)) {  
89.                      return;  
90.                  }  
91.             }  
92.  //否则交给派生处理,基类默认处理是什么都不干  
93.              handleMessage(msg);  
94.          }  
95.      }  
96.  ..........  
97.  }  


 讲了这么多,该怎么创建和使用一个带消息循环的线程呢?

1.  //假设在onCreate中创建一个线程  
2.  //不花时间考虑代码的完整和严谨性了,以讲述原理为主。  
3.  ....  
4.    
5.  ... onCreate(...){  
6.    
7.  //难点是如何把android中的looper和java的thread弄到一起去。  
8.  //而且还要把随时取得这个looper用来创建handler  
9.  //最简单的办法就是从Thread派生一个  
10.  class ThreadWithMessageHandle extends Thread{  
11.    //重载run函数  
12.    Looper myLooper = null;  
13.    run(){  
14.    Looper.prepare();//将Looper设置到这个线程中  
15.    myLooper = Looper.myLooper();  
16.    Looper.loop();开启消息循环  
17.  }  
18.    
19.   ThreadWithMessageHandle  threadWithMgs = new ThreadWithMessageHandle();  
20.   threadWithMsg.start();  
21.   Looper looper = threadWithMsg.myLooper;//  
22.  //这里有个问题.threadWithMgs中的myLooper可能此时为空  
23.  //需要同步处理一下  
24.  //或者像API文档中的那样,把handler定义到ThreadWithMessageHandle到去。  
25.  //外线程获得这个handler的时候仍然要注意同步的问题,因为handler的创建是在run中的  
26.   Handler threadHandler = new Handler(looper);  
27.   threadHandler.sendMessage(...)  
28.  }  
29.    
30.    
31.  }  
32.    
33.    
34.    
35.  ...  


好了,handler和looper的分析就都这了,其实原理挺简单的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值