Android消息处理机制

一、    角色描述

1.Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的Message Queue(消息队列)。

2.Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的消息。

3. Message Queue(消息队列):用来存放线程放入的消息。

4.线程:UI thread 通常就是main thread,而Android启动程序时会替它建立一个Message Queue。

每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。

 

在你的Android程序里,新诞生一个线程,或执行 (Thread)时,并不会自动建立其Message Loop。

Android里并没有Global的Message Queue数据结构,例如,不同APK里的对象不能透过Massage Queue来交换讯息(Message)。

例如:线程A的Handler对象可以传递消息给别的线程,让别的线程B或C等能送消息来给线程A(存于A的Message Queue里)。

线程A的Message Queue里的讯息,只有线程A所属的对象可以处理。

使用Looper.myLooper可以取得当前线程的Looper对象。

使用mHandler = new EevntHandler(Looper.myLooper()); 可用来构造当前线程的Handler对象;其中,EevntHandler是自已实现的Handler的子类别。

使用mHandler = new EevntHandler(Looper.getMainLooper()); 可诞生用来处理main线程的Handler对象;其中,EevntHandler是自已实现的Handler的子类别。

 

这样描述可能太抽像,下面举几个实际的例子来说明:

二、    举例

1.  同线程内不同组件间的消息传递

Looper类用来管理特定线程内对象之间的消息交换(Message Exchange)。你的应用程序可以产生许多个线程。而一个线程可以有许多个组件,这些组件之间常常需要互相交换讯息。如果有这种需要,您可以替线程构造一个Looper对象,来担任讯息交换的管理工作。Looper对象会建立一个MessageQueue数据结构来存放各对象传来的消息(包括UI事件或System事件等)。如下图:

每一个线程里可含有一个Looper对象以及一个MessageQueue数据结构。在你的应用程序里,可以定义Handler的子类别来接收Looper所送出的消息。

同线程不同组件之间的消息传递:

public class Activity1 extends Activity implements OnClickListener{

       Button button = null;

       TextView text = null;

       @Override

       protected void onCreate(Bundle savedInstanceState) {

              super.onCreate(savedInstanceState);

              setContentView(R.layout.activity1);        

              button = (Button)findViewById(R.id.btn);

              button.setOnClickListener(this);

              text = (TextView)findViewById(R.id.content);

       }

       public void onClick(View v) {

              switch (v.getId()) {

              case R.id.btn:

                     Looper looper = Looper.myLooper();//取得当前线程里的looper

                     MyHandler mHandler = new MyHandler(looper);//构造一个handler使之可与looper通信

                     //buton等组件可以由mHandler将消息传给looper后,再放入messageQueue中,同时mHandler也可以接受来自looper消息

                     mHandler.removeMessages(0);

                     String msgStr = "主线程不同组件通信:消息来自button";

                     Message m = mHandler.obtainMessage(1, 1, 1, msgStr);//构造要传递的消息

                     mHandler.sendMessage(m);//发送消息:系统会自动调用handleMessage方法来处理消息

                     break;

 

              }            

       }     

       private class MyHandler extends Handler{             

              public MyHandler(Looper looper){

                     super(looper);

              }

              @Override

              public void handleMessage(Message msg) {//处理消息

                     text.setText(msg.obj.toString());

              }            

       }

}


 

说明:

此程序启动时,当前线程(即主线程, main thread)已诞生了一个Looper对象,并且有了一个MessageQueue数据结构。

    looper = Looper.myLooper (); 

调用Looper类别的静态myLooper()函数,以取得目前线程里的Looper对象.

mHandler = new MyHandler (looper);

构造一个MyHandler对象来与Looper沟通。Activity等对象可以藉由MyHandler对象来将消息传给Looper,然后放入MessageQueue里;MyHandler对象也扮演Listener的角色,可接收Looper对象所送来的消息。

Message m = mHandler.obtainMessage(1, 1, 1, obj);

先构造一个Message对象,并将数据存入对象里。

mHandler.sendMessage(m);

就透过mHandler对象而将消息m传给Looper,然后放入MessageQueue里。

此时,Looper对象看到MessageQueue里有消息m,就将它广播出去,mHandler对象接到此讯息时,会呼叫其handleMessage()函数来处理,于是输出"This my message!"于画面上,

角色综述(回顾):

   (1)UI thread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。

(2)当然需要一个Looper对象,来管理该MessageQueue。

(3)我们可以构造Handler对象来push新消息到Message Queue里;或者接收Looper(从Message Queue取出)所送来的消息。

(4)线程A的Handler对象可以传递给别的线程,让别的线程B或C等能送讯息来给线程A(存于A的Message Queue里)。

(5)线程A的Message Queue里的消息,只有线程A所属的对象可以处理。

 

子线程传递消息给主线程

public class Activity2 extends Activity implements OnClickListener{

       Button button = null;

       TextView text = null;

       MyHandler mHandler = null;

       Thread thread ;

       @Override

       protected void onCreate(Bundle savedInstanceState) {

              super.onCreate(savedInstanceState);

              setContentView(R.layout.activity1);        

              button = (Button)findViewById(R.id.btn);

              button.setOnClickListener(this);

              text = (TextView)findViewById(R.id.content);

       }

       public void onClick(View v) {

              switch (v.getId()) {

              case R.id.btn:

                     thread = new MyThread();

                     thread.start();

                     break;

              }            

       }     

       private class MyHandler extends Handler{             

              public MyHandler(Looper looper){

                     super(looper);

              }

              @Override

              public void handleMessage(Message msg) {//处理消息

                     text.setText(msg.obj.toString());

              }            

       }

       private class MyThread extends Thread{

              @Override

              public void run() {

                     Looper curLooper = Looper.myLooper();

                     Looper mainLooper = Looper.getMainLooper();

                     String msg ;

                     if(curLooper==null){

                            mHandler = new MyHandler(mainLooper);

                            msg = "curLooper is null";

                     }else{

                            mHandler = new MyHandler(curLooper);

                            msg = "This is curLooper";

                     }

                     mHandler.removeMessages(0);

                     Message m = mHandler.obtainMessage(1, 1, 1, msg);

                     mHandler.sendMessage(m);

              }            

       }

}


说明:

Android会自动替主线程建立Message Queue。在这个子线程里并没有建立Message Queue。所以,myLooper值为null,而mainLooper则指向主线程里的Looper。于是,执行到:

mHandler = new MyHandler (mainLooper);

此mHandler属于主线程。

   mHandler.sendMessage(m);

就将m消息存入到主线程的Message Queue里。mainLooper看到Message Queue里有讯息,就会作出处理,于是由主线程执行到mHandler的handleMessage()来处理消息。

上面这个例子还不是很好,下面转别的博客的一个关于线程间通讯的例子:

andriod提供了 Handler 和 Looper 来满足线程间的通信。例如一个子线程从网络上下载了一副图片,当它下载完成后会发送消息给主线程,这个消息是通过绑定在主线程的Handler来传递的。

在Android,这里的线程分为有消息循环的线程和没有消息循环的线程,有消息循环的线程一般都会有一个Looper,这个是android的新概念。我们的主线程(UI线程)就是一个消息循环的线程。针对这种消息循环的机制,我们引入一个新的机制Handler,我们有消息循环,就要往消息循环里 面发送相应的消息,自定义消息一般都会有自己对应的处理,消息的发送和清除,消息的的处理,把这些都封装在Handler里面,注意Handler只是针对那 些有Looper的线程,不管是UI线程还是子线程,只要你有Looper,我就可以往你的消息队列里面添加东西,并做相应的处理。但是这里还有一点,就是只要是关于UI相关的东西,就不能放在子线程中,因为子线程是不能操作UI的,只能进行数据、系统等其他非UI的操作。

一个Handler的创建它就会被绑定到这个线程的消息队列中,如果是在主线程创建的,那就不需要写代码来创建消息队列了,默认的消息队列会在主线程被创建。但是如果是在子线程的话,就必须在创建Handler之前先初始化线程的消息队列。如下面的代码:

class ChildThread extends Thread {
 
    public void run() {
 
        /**
         * 创建 Handler前先初始化Looper.
         */
        Looper.prepare();
 
        /**
         * 在子线程创建handler,所以会绑定到子线程的消息队列中
         *
         */
        mChildHandler = new Handler() {
 
            public void handleMessage(Message msg) {
 
                /**
                 * Do some expensive operations there.
                 */
            }
        };
 
        /**
         * 启动该线程的消息队列
         */
        Looper.loop();
    }
}

当Handler收到消息后,就会运行handleMessage(…)的回调函数,可以在里面做一些耗时的操作。

最后完成了操作要结束子线程时,记得调用quit()来结束消息循环队列。

mChildHandler.getLooper().quit();

下面是一个线程间通信的小例子:

/**
 *
 * @author andy
 * http://www.zeroup.org/
 *
 */
public class MainThread extends Activity {
 
    private static final String TAG = "MainThread";
    private Handler mMainHandler, mChildHandler;
    private TextView info;
    private Button msgBtn;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        info = (TextView) findViewById(R.id.info);
        msgBtn = (Button) findViewById(R.id.msgBtn);
 
        mMainHandler = new Handler() {
 
            @Override
            public void handleMessage(Message msg) {
                Log.i(TAG, "Got an incoming message from the child thread - "
                        + (String) msg.obj);
                // 接收子线程的消息
                info.setText((String) msg.obj);
            }
 
        };
 
        new ChildThread().start();
 
        msgBtn.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View v) {
 
                if (mChildHandler != null) {
 
                    //发送消息给子线程
                    Message childMsg = mChildHandler.obtainMessage();
                    childMsg.obj = mMainHandler.getLooper().getThread().getName() + " says Hello";
                    mChildHandler.sendMessage(childMsg);
 
                    Log.i(TAG, "Send a message to the child thread - " + (String)childMsg.obj);
 
                }
            }
        });
 
    }
 
    public void onDestroy() {
      super.onDestroy();
        Log.i(TAG, "Stop looping the child thread's message queue");
 
        mChildHandler.getLooper().quit();
    }
 
    class ChildThread extends Thread {
 
        private static final String CHILD_TAG = "ChildThread";
 
        public void run() {
            this.setName("ChildThread");
 
            //初始化消息循环队列,需要在Handler创建之前
            Looper.prepare();
 
            mChildHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                     Log.i(CHILD_TAG, "Got an incoming message from the main thread - " + (String)msg.obj);
 
                    try {
 
                        //在子线程中可以做一些耗时的工作
                        sleep(100);
 
                        Message toMain = mMainHandler.obtainMessage();
                        toMain.obj = "This is " + this.getLooper().getThread().getName() +
                                    ".  Did you send me \"" + (String)msg.obj + "\"?";
 
                        mMainHandler.sendMessage(toMain);
 
                        Log.i(CHILD_TAG, "Send a message to the main thread - " + (String)toMain.obj);
 
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
 
            };
 
            Log.i(CHILD_TAG, "Child handler is bound to - "+ mChildHandler.getLooper().getThread().getName());
 
            //启动子线程消息循环队列
            Looper.loop();
        }
    }
}

使用上面的方法容易产生线程同步问题,android提供了一个更好的类HandlerThread解决这个问题。

package mars.handler;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;

public class HandlerTest2 extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  // TODO Auto-generated method stub
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  //打印了当前线程的ID
  System.out.println("Activity-->" + Thread.currentThread().getId());
  //生成一个HandlerThread对象,实现了使用Looper来处理消息队列的功能,这个类由Android应用程序框架提供
  HandlerThread handlerThread = new HandlerThread("handler_thread");
  //在使用HandlerThread的getLooper()方法之前,必须先调用该类的start();
  handlerThread.start();
  MyHandler myHandler = new MyHandler(handlerThread.getLooper());
  Message msg = myHandler.obtainMessage();
  //将msg发送到目标对象,所谓的目标对象,就是生成该msg对象的handler对象
  Bundle b = new Bundle();
  b.putInt("age", 20);
  b.putString("name", "Jhon");
  msg.setData(b);
  msg.sendToTarget();
 }
 
 //继承Handler类,
 class MyHandler extends Handler{
  public MyHandler(){
   
  }
  public MyHandler(Looper looper){
   super(looper);
  }
  @Override
  public void handleMessage(Message msg) {
   Bundle b = msg.getData();
   int age = b.getInt("age");
   String name = b.getString("name");
   System.out.println("age is " + age + ", name is" + name);

  }
 }
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值