Android消息处理学习笔记

来源:互联网 发布:seo外链推广 编辑:程序博客网 时间:2024/06/05 19:03

Looper

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

Most interaction with a message loop is through the Handler class.

Looper类用来为线程执行消息循环。默认情况下线程没有关联消息循环,为了创建一个消息循环,在运行循环的线程中调用prepare()方法,然后调用loop()方法处理消息。

大多数情况下与消息循环交互是通过Handler类。

例如下面这个例子,你的线程就具有了消息处理机制了,在Handler中进行消息处理。

class LooperThread extends Thread {

public Handler mHandler;      public void run() {          Looper.prepare();          mHandler = new Handler() {              public void handleMessage(Message msg) {                  // process incoming messages here              }          };          Looper.loop();      }  }

Handler

A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.

Handler允许你发送和处理与线程MessageQueue关联的Message和Runnable对象。每个Handler实例与一个线程及线程的消息队列关联。当你创建一个新的Handler,它与创建它的线程及消息队列绑定,这意味着,它将给消息队列发送消息和runnalbe对象,并且当消息和runnalbe对象从消息队列出来时候处理它们。

Scheduling messages is accomplished with the post(Runnable)postAtTime(Runnable, long)postDelayed(Runnable, long)sendEmptyMessage(int),sendMessage(Message)sendMessageAtTime(Message, long), and sendMessageDelayed(Message, long) methods. The post versions allow you to enqueue Runnable objects to be called by the message queue when they are received; the sendMessage versions allow you to enqueue a Message object containing a bundle of data that will be processed by the Handler's handleMessage(Message) method (requiring that you implement a subclass of Handler).

调度消息有两种版本。post版本允许你把Runnable对象放入消息队列。sendMessage版本允许你把一个Message对象放入消息队列。Message可以包含一组数据,它将被Handler的handleMessage(Message)方法处理(需要你实现一个Handle类的子类)。

When a process is created for your application, its main thread is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. You can create your own threads, and communicate back with the main application thread through a Handler. This is done by calling the same post or sendMessage methods as before, but from your new thread. The given Runnable or Message will then be scheduled in the Handler's message queue and processed when appropriate.

当进程为你的应用程序创建后,它的主线程致力于运行一个消息队列来照顾顶层应用对象(activities, broadcast receiver等)和应用对象创建的窗口。你能创建自己的线程,并通过Handler与应用程序的主线程进行通信。这通过调研前面提到的post或sendMessage方法实现,但是注意必须在你的新线程中调用。

下面接着摘自:http://my.unix-center.net/~Simon_fu/?p=652

     Activity是一个UI线程,运行于主线程中,Android系统在启动的时候会为Activity创建一个消息队列和消息循环(Looper)。详细实现请参考ActivityThread.java文件。

     Handler的作用是把消息加入特定的(Looper)消息队列中,并分发和处理该消息队列中的消息。构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper创建。详细实现请参考Looper的源码。

     一个Activity中可以创建多个工作线程或者其他的组件,如果这些线程或者组件把他们的消息放入Activity的主线程消息队列,那么该消息就会在主线程中处理了。因为主线程一般负责界面的更新操作,并且Android系统中的weget不是线程安全的,所以这种方式可以很好的实现Android界面更新。在Android系统中这种方式有着广泛的运用。

     那么另外一个线程怎样把消息放入主线程的消息队列呢?答案是通过Handle对象,只要Handler对象以主线程的Looper创建,那么调用Handler的sendMessage等接口,将会把消息放入队列都将是放入主线程的消息队列。并且将会在Handler主线程中调用该handler的handleMessage接口来处理消息。

public class MyHandler extends Activity {static final String TAG = "Handler";Handler h = new Handler(){    public void handleMessage (Message msg)    {    switch(msg.what)    {    case HANDLER_TEST:    Log.d(TAG, "The handler thread id = " + Thread.currentThread().getId() + "\n");    break;    }    }    };static final int HANDLER_TEST = 1;    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d(TAG, "The main thread id = " + Thread.currentThread().getId() + "\n");        new myThread().start();        setContentView(R.layout.main);    }    class myThread extends Thread    {    public void run()    {    Message msg = new Message();    msg.what = HANDLER_TEST;    h.sendMessage(msg);    Log.d(TAG, "The worker thread id = " + Thread.currentThread().getId() + "\n");    }    }}

上例中,你可能注意到在工作线程中访问了主线程handler对象,并在调用handler的对象向消息队列加入了一个消息。这个过程中会不会出现消息队列数据不一致问题呢?答案是handler对象不会出问题,因为handler对象管理的Looper对象是线程安全的,不管是加入消息到消息队列和从队列读出消息都是有同步对象保护的,具体请参考Looper.java文件。上例中没有修改handler对象,所以handler对象不可能会出现数据不一致的问题。

     通过上面的分析,我们可以得出如下结论:

1、如果通过工作线程刷新界面,推荐使用handler对象来实现。

2、注意工作线程和主线程之间的竞争关系。推荐handler对象在主线程中构造完成(并且启动工作线程之后不要再修改之,否则会出现数据不一致),然后在工作线程中可以放心的调用发送消息SendMessage等接口。

3、除了2所述的hanlder对象之外的任何主线程的成员变量如果在工作线程中调用,仔细考虑线程同步问题。如果有必要需要加入同步对象保护该变量。

4、handler对象的handleMessage接口将会在主线程中调用。在这个函数可以放心的调用主线程中任何变量和函数,进而完成更新UI的任务。

5、Android很多API也利用Handler这种线程特性,作为一种回调函数的变种,来通知调用者。这样Android框架就可以在其线程中将消息发送到调用者的线程消息队列之中,不用担心线程同步的问题。

     深入理解Android消息处理机制对于应用程序开发非常重要,也可以让你对线程同步有更加深刻的认识。以上是最近Simon学习Android消息处理机制的一点儿总结,如有错误之处请不吝指教。

HandlerThread

Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

这是一个便利类,用来启动一个含有looper的新线程。这个looper用来创建handler类。注意,必须调用start()。