Handler与Looper的关系

本文详细解析Android中的消息机制,通过源码分析,深入理解Looper与Handler的交互过程,包括消息队列的创建、消息的投递与处理等关键步骤。

源:http://blog.youkuaiyun.com/illusion_luna/article/details/8222657

先来看一下Looper这个类:


再来看一下handler这个类的google给出的解释:

简单的来说:大家可以这样来理解,有一个消息队列MessageQueue(队列应该大家都知道了吧。。。。。),我们handler要做的工作就是将一个Message对象都到这个消息队列和负责处理从被消息队列拿出来的Message,那么谁负责遍历和拿取消息队列内的消息给handler呢?没错,这些遍历和拿取的工作就是Looper来完成的。好了,下面来看一下我写的例子(如果有大神飘过的话,别见怪。。别见怪。。。偷笑)

先来看一下整个项目的搭构:

其中的布局文件main.xml里面很简单,久一个TextView和一个Button。(不信的话。。。。。我也不给你看大笑)

好了,现在我们来看一下activity里面的代码

[java]  view plain copy print ?
  1. public class HLActivity extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     private TextView textView=null;  
  4.     private Button btn=null;  
  5.     //private Handler handler=null;  
  6.     public static int i=0;  
  7.     @Override  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.main);  
  11.         initralWeight();  
  12.         /*handler=new Handler(){ 
  13.             @Override 
  14.             public void handleMessage(Message msg) { 
  15.                 // TODO Auto-generated method stub 
  16.                 textView.setText("当前点击运行线程的次数为"+msg.arg1); 
  17.             } 
  18.         };*/  
  19.           
  20.     }  
  21.     private class BtnListener implements OnClickListener{  
  22.   
  23.         @Override  
  24.         public void onClick(View v) {  
  25.             // TODO Auto-generated method stub  
  26.               
  27.             TestThread tt=new TestThread();  
  28.             Thread t=new Thread(tt);  
  29.             t.start();  
  30.         }  
  31.           
  32.     }  
  33.     private class TestThread implements Runnable{  
  34.         private Handler handler=null;  
  35.         @Override  
  36.         public void run() {  
  37.             // TODO Auto-generated method stub  
  38.             Looper.prepare();  
  39.             handler=new Handler(){  
  40.                 @Override  
  41.                 public void handleMessage(Message msg) {  
  42.                     // TODO Auto-generated method stub  
  43.                     System.out.println("当前的数字为:"+msg.arg1);  
  44.                 }  
  45.             };  
  46.             while(i<10){  
  47.                 Message msg=new Message();  
  48.                 msg.arg1=i++;  
  49.                 handler.sendMessage(msg);  
  50.             }  
  51.             Looper.loop();  
  52.         }  
  53.           
  54.     }  
  55.     private void initralWeight(){  
  56.         textView=(TextView) findViewById(R.id.text);  
  57.         btn=(Button) findViewById(R.id.btn);  
  58.         btn.setOnClickListener(new BtnListener());  
  59.     }  
  60. }  
功能很简单,当点击Button时,就会开启线程,而这个线程就会不断的i++,然后生成个Message对象,将其投递到消息队列里面去。然后

[java]  view plain copy print ?
  1. handler=new Handler(){  
  2.         @Override  
  3.         public void handleMessage(Message msg) {  
  4.          // TODO Auto-generated method stub  
  5.          System.out.println("当前的数字为:"+msg.arg1);  
  6.     }  
  7. };  
这部分的代码就是负责处理从消息队列内拿取的消息,那么这里又有人问了,
[java]  view plain copy print ?
  1. Looper.prepare();  
[java]  view plain copy print ?
  1. Looper.loop();  
到底是有什么用的?

还有,你说的消息队列到底在哪里?为什么我没看见?

别急,下面我们来看一下关于Looper的源代码:

[java]  view plain copy print ?
  1. public class Looper {  
  2.     // 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象  
  3.     private static final ThreadLocal sThreadLocal = new ThreadLocal();  
  4.     // Looper内的消息队列  
  5.     final MessageQueue mQueue;  
  6.     // 当前线程  
  7.     Thread mThread;  
  8.     // 。。。其他属性  
  9.   
  10.     // 每个Looper对象中有它的消息队列,和它所属的线程  
  11.     private Looper() {  
  12.         mQueue = new MessageQueue();  
  13.         mRun = true;  
  14.         mThread = Thread.currentThread();  
  15.     }  
  16.   
  17.     // 我们调用该方法会在调用线程的TLS中创建Looper对象  
  18.     public static final void prepare() {  
  19.         if (sThreadLocal.get() != null) {  
  20.             // 试图在有Looper的线程中再次创建Looper将抛出异常  
  21.             throw new RuntimeException("Only one Looper may be created per thread");  
  22.         }  
  23.         sThreadLocal.set(new Looper());  
  24.     }  
  25.     // 其他方法  
  26. }  

大家在这里可以看到Looper的构造函数Looper()被声明为private,也就是说,在外部,我们不能直接的使用Looper的构造函数,那么我们该怎样去创建一个Looper对象呢?

[java]  view plain copy print ?
  1. public static final void prepare() {  
  2.        if (sThreadLocal.get() != null) {  
  3.            // 试图在有Looper的线程中再次创建Looper将抛出异常  
  4.            throw new RuntimeException("Only one Looper may be created per thread");  
  5.        }  
  6.        sThreadLocal.set(new Looper());  
  7.    }  
prepare()这个函数为我们提供了初始化Looper对象的功能,在这里不了解ThreadLocal是什么的可以去看一下我上一篇博客,就是介绍ThreadLocal,好了在这里我不多说了。。。,而这个函数我们要注意它给我们什么信息了。很显然,它告诉我,们只要你调用这个方法,那么系统就会在ThreadLocal内添加一个Looper对象,并且一个线程只能有一个Looper,若超出一个,则会抛出异常。。。。。。

好了,下面是重点:

[java]  view plain copy print ?
  1. public static final void loop() {  
  2.        Looper me = myLooper();  //得到当前线程Looper  
  3.        MessageQueue queue = me.mQueue;  //得到当前looper的MQ  
  4.          
  5.        // 这两行没看懂= = 不过不影响理解  
  6.        Binder.clearCallingIdentity();  
  7.        final long ident = Binder.clearCallingIdentity();  
  8.        // 开始循环  
  9.        while (true) {  
  10.            Message msg = queue.next(); // 取出message  
  11.            if (msg != null) {  
  12.                if (msg.target == null) {  
  13.                    // message没有target为结束信号,退出循环  
  14.                    return;  
  15.                }  
  16.                // 日志。。。  
  17.                if (me.mLogging!= null) me.mLogging.println(  
  18.                        ">>>>> Dispatching to " + msg.target + " "  
  19.                        + msg.callback + ": " + msg.what  
  20.                        );  
  21.                // 非常重要!将真正的处理工作交给message的target,即后面要讲的handler  
  22.                msg.target.dispatchMessage(msg);  
  23.                // 还是日志。。。  
  24.                if (me.mLogging!= null) me.mLogging.println(  
  25.                        "<<<<< Finished to    " + msg.target + " "  
  26.                        + msg.callback);  
  27.                  
  28.                // 下面没看懂,同样不影响理解  
  29.                final long newIdent = Binder.clearCallingIdentity();  
  30.                if (ident != newIdent) {  
  31.                    Log.wtf("Looper""Thread identity changed from 0x"  
  32.                            + Long.toHexString(ident) + " to 0x"  
  33.                            + Long.toHexString(newIdent) + " while dispatching to "  
  34.                            + msg.target.getClass().getName() + " "  
  35.                            + msg.callback + " what=" + msg.what);  
  36.                }  
  37.                // 回收message资源  
  38.                msg.recycle();  
  39.            }  
  40.        }  
  41.    }  
当我们调用Looper.loop()这个方法后,Looper才真正的开始工作
[java]  view plain copy print ?
  1. Looper me = myLooper();  //得到当前线程Looper  
  2. MessageQueue queue = me.mQueue;  //得到当前looper的MQ  
获取到当前Looper的MessageQueue,每一个Looper都有一个消息队列,并且这个消息队列作为Looper的一个成员属性。

然后再while内循环这个消息队列,不断的取出数据

[java]  view plain copy print ?
  1. Message msg = queue.next(); // 取出message  
先判断该消息队列是否到底了。。。
[java]  view plain copy print ?
  1. if (msg != null)  
[java]  view plain copy print ?
  1. if (msg.target == null) {  
  2.       // message没有target为结束信号,退出循环  
  3.       return;  
  4. }  
接着便是一系列的打印日志:
[java]  view plain copy print ?
  1. <pre name="code" class="java">// 日志。。。  
  2.                 if (me.mLogging!= null) me.mLogging.println(  
  3.                         ">>>>> Dispatching to " + msg.target + " "  
  4.                         + msg.callback + ": " + msg.what  
  5.                         );</pre>  
  6. <pre></pre>  
  7. <pre></pre>  
  8. 在下面便是这个方法的核心了。<pre name="code" class="java">msg.target.dispatchMessage(msg);</pre>这个方法实际作用便是将Message传递给Handler类来处理,而Handler使用<pre name="code" class="java">handleMessage</pre>方法来接受,并且处理该信息。  
  9. <p>有些人说了</p>  
  10. <pre name="code" class="java">dispatchMessage</pre>是Handler的方法吧?别急。  
  11. <p>下面我们来看一下dispatchMessage这个方法的内部实现:<span style="color:#008000"><br>  
  12. </span></p>  
  13. <p><span style="color:#008000">//</span><span style="color:#008000"> 处理消息,该方法由looper调用</span><span style="color:#008000"></span><span style="color:#000000">  
  14. </span><span style="color:#0000ff">public</span><span style="color:#000000"> </span>  
  15. <span style="color:#0000ff">void</span><span style="color:#000000"> dispatchMessage(Message msg) {  
  16. </span><span style="color:#0000ff">if</span><span style="color:#000000"> (msg.callback  
  17. </span><span style="color:#000000">!=</span><span style="color:#000000"> </span><span style="color:#0000ff">null</span><span style="color:#000000">) {  
  18. </span><span style="color:#008000">//</span><span style="color:#008000"> 如果message设置了callback,即runnable消息,处理callback!</span><span style="color:#008000"></span><span style="color:#000000"> handleCallback(msg); }  
  19. </span><span style="color:#0000ff">else</span><span style="color:#000000"> { </span>  
  20. <span style="color:#008000">//</span><span style="color:#008000"> 如果handler本身设置了callback,则执行callback</span><span style="color:#008000"></span><span style="color:#000000">  
  21. </span><span style="color:#0000ff">if</span><span style="color:#000000"> (mCallback  
  22. </span><span style="color:#000000">!=</span><span style="color:#000000"> </span><span style="color:#0000ff">null</span><span style="color:#000000">) {  
  23. </span><span style="color:#008000">/*</span><span style="color:#008000"> 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。见http://alex-yang-xiansoftware-com.iteye.com/blog/850865 
  24. </span><span style="color:#008000">*/</span><span style="color:#000000"> </span><span style="color:#0000ff">if</span><span style="color:#000000"> (mCallback.handleMessage(msg)) {  
  25. </span><span style="color:#0000ff">return</span><span style="color:#000000">; } }  
  26. </span><span style="color:#008000">//</span><span style="color:#008000"> 如果message没有callback,则调用handler的钩子方法handleMessage</span><span style="color:#008000"></span><span style="color:#000000"> handleMessage(msg); } }</span></p>  
  27. 可以看到了吧,在dispatchMessage这个方法内有这么的一句代码:  
  28. <pre><span style="color:#000000"> handleMessage(msg);</span></pre>  
  29. 呵呵呵呵呵呵~~~~~我想现在大家都应该明白了吧,Handler与Looper两者之间的关系和调用。。。。。。<br>  
  30. <p></p>  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值