代码改变世界

Handler的使用(二)

2012-05-13 01:03  ...平..淡...  阅读(449)  评论(0编辑  收藏  举报
简单描述如下:

Looper类 是用来封装消息循环消息队列的一个类。
handler 其实可以看做是一个工具类,通过Looper类向消息队列中插入消息,然后通过Looper类从消息队列中提取消息让handler类来处理消息的。

ps:可以通过Loop.myLooper()
可以得到当前线程的Looper对象,通过Loop.getMainLooper()可以获得当前进程的主线程的Looper对象。默认情况下建立的handler都是与当前线程的looper相关的,但是也可以获取主线程的looper,然后在子线程中建立主线程的handler

HandlerThread 类实现了循环处理消息的功能,所以在本文程序中我没有定义Looper类对象,直接通过HandlerThread的getLooper方法获取。

MessageQueue负责存储有关某一个线程(通常是主线程)的所有消息,而Looper则负责管理消息队列,Handler负责向消息队列发送消息和处理消息~

 

分析以下两种情况:

1.handler与主activity在同一个线程的情况:

使用post方法来把线程对象放到消息队列中,是直接调用线程对象的run方法,其实没有开启新的线程. 因为线程都需要通过start方法来启动,而handler没有通过线程的start方法来启动线程,所以它们是处于同一线程。

 

2.创建子线程的情况:

生成HandlerThread类的对象,然后调用start方法,产生新的线程,然后再创建Handler对象(MyHandler继承自Handler)。

MyHandler myHandler = new MyHandler(handlerThread.getLooper());

之后操作同"handler的使用(一)"。

 

 

下面详解转自http://byandby.iteye.com/blog/825071

  

比如我想在子线程中定义一个字符串,然后通过发消息的方式,Message把这个字符串发送给主线程也就是UI线程,让UI线程来设置这个TextView的值为我们刚刚在子线程中定义的字符串。或者我想在子线程中开启音乐服务,或者把它停止该怎么做呢?要知道怎么做先让我们了解一下这几个对象吧!它们分别是 MessageQueue、Handler、Looper。

  

在单线程模型下,为了解决类似的问题,Android设计了一个Message Queue(消息队列), 线程间可以通过该Message Queue并结合Handler和Looper组件进行信息交换。
 

1.Message Queue 

  Message Queue是一个消息队列,用来存放通过Handler发布的消息。消息队列通常附属于某一个创建它的线程,可以通过Looper.myQueue()得到当前线程的消息队列。如果没有消息队列对象则会抛出空指针异常。Android在第一次启动程序时会默认会为UI thread创建一个关联的消息队列,用来管理程序的一些上层组件,如activities,broadcast receivers 等等。你可以在自己的子线程中创建Handler与UI thread通讯。也就是说我们程序一启动我们的UI线程也就是主线程就会有一个消息队列,而如果我们自己另外开启的一个子线程就不会有MessageQueue(消息队列)对象。这一点大家务必知道。 

2. Handler 

  通过Handler你可以发布或者处理一个消息或者是一个Runnable的实例。每个Handler都会与唯一的一个线程以及该线程的消息队列关联。当你创建一个新的Handler时候,默认情况下,它将关联到创建它的这个线程和该线程的消息队列。也就是说,如果你通过Handler发布消息的话,消息将只会发送到与它关联的这个消息队列,当然也只能处理该消息队列中的消息。这里大家就得理解一下了 也就是说我们一个Handler对应一个线程以及附属于该线程的消息队列。 

 

3. Looper 

  Looper扮演着一个Handler和消息队列之间通讯桥梁的角色。程序组件首先通过Handler把消息传递给Looper,Looper把消息放入队列。Looper也把消息队列里的消息广播给所有的Handler,Handler接受到消息后调用handleMessage进行处理。 

1)可以通过Looper类 的静态方法Looper.myLooper()得到当前线程的Looper实例,如果当前线程未关联一个Looper实例,该方法将返回空(null)它不会抛空指针异常。 

2)可以通过静态方法Looper. getMainLooper()方法得到主线程的Looper实例。这里需要注意一下,主线程默认是有一个Looper对象的,但是我们自己定义的子线程没有的。那么我们怎么在子线程中得到Looper对象呢?如果一个线程中调用Looper.prepare(),那么系统就会自动的为该线程建立一个消息队列,然后调用Looper.loop();之后就进入了消息循环,之后就可以发消息、取消息、和处理消息。这个如何发送消息和如何处理消息可以在其他的线程中通过Handle来做,但前提是我们的Handler知道这个子线程的Looper,但是你如果不是在子线程运行Looper.myLooper(),一般是得不到子线程的looper的。

 

 

比上面解释劲爆的多的多的解释!!!!

发现的太晚了,留着上面那种解释,来对比

Handler
 
消息的封装者和处理者,handler负责将需要传递的信息封装成Message,通过调用handler对象的obtainMessage()来实现;将消息传递给Looper,这是通过handler对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法对其进行处理。
 
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实例。
 
MessageQueue
 
是一种数据结构,见名知义,就是一个消息队列,存放消息的地方。每一个线程最多只可以拥有一个MessageQueue数据结构。创建一个线程的时候,并不会自动创建其MessageQueue。通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个Message Queue。其他非主线程,不会自动创建Looper,要需要的时候,通过调用prepare函数来实现。
 
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中。

 

 

使用HandlerThread来简单进行程序演示

step1:新建android工程,命名为HandlerTest2.

step3:主Activity程序..

 1 HandlerTest2
 2  package com.cb.handler;
 3  
 4  import android.app.Activity;
 5  import android.os.Bundle;
 6  import android.os.Handler;
 7  import android.os.HandlerThread;
 8  import android.os.Looper;
 9  import android.os.Message;
10  import android.view.View;
11  import android.view.View.OnClickListener;
12  import android.widget.Button;
13  import android.widget.ProgressBar;
14  
15  public class HandlerTest2 extends Activity {
16      @Override
17      public void onCreate(Bundle savedInstanceState) {
18          super.onCreate(savedInstanceState);
19          setContentView(R.layout.main);
20  //        handler.post(r);
21          
22          //生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,这个类由android应用程序框架提供。
23          HandlerThread handlerThread = new HandlerThread("Handler_Thread");
24          //在使用HandlerThread的getLooper方法之前,必须先调用该类的start方法,否则getLooper方法取出的值是空值。
25          handlerThread.start();
26          
27          //
28          MyHandler myHandler = new MyHandler(handlerThread.getLooper());
29          Message msg = myHandler.obtainMessage();
30          
31          Bundle bundle = new Bundle();
32          bundle.putString("name", "cb");
33          bundle.putInt("age", 20);
34          msg.setData(bundle);
35          
36          //将msg对象发送到目标对象,所谓的目标对象就是生成该msg对象的Handler对象。
37          msg.sendToTarget();
38  
39          System.out.println("activity---->"+Thread.currentThread().getId());
40          System.out.println("activity---->"+Thread.currentThread().getName());
41      }
42      
43      class MyHandler extends Handler {
44          public  MyHandler() {}
45          
46          public  MyHandler(Looper looper) {
47              super(looper);
48          }
49          
50          @Override
51          public void handleMessage(Message msg) {
52              System.out.println("handler------>"+Thread.currentThread().getId());
53              System.out.println("handler------>"+Thread.currentThread().getName());
54          }
55          
56      }
57  }

 

step4:图示结果

因为handler(id号与name值) 和activity的不同,说明确实创建了新的子线程。