Android消息机制

来源:互联网 发布:汗脚引起灰指甲知乎 编辑:程序博客网 时间:2024/04/27 20:38

在Android中,主线程UI线程不是线程安全的,对UI的更新只能在UI线程中执行,在工作线程中执行UI更新操作,会抛出android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.  错误。

为了实现工作线程对UI线程的操作,以及线程间通信,Android中设计了一套消息机制。

Android消息机制主要有Looper、Handler、Message和MessageQueue几个类组成。

借用下别人的图片,各组件的关系如下:


Looper

每个线程只能有一个Looper(其实Looper是一个ThreadLocal对象),Looper主要实现对MessageQueue中的Message信息的消费。

UI线程启动的时候,默认绑定了一个Looper。

对于工作线程可通过Looper.prepare()和Looper.loop()简单的两步,把线程变为LooperThread,实现线程对消息的消费。并为工作线程实例化Handler对象,用于消息的发送和处理。

Looper.prepare()静态方法:

private static final ThreadLocal sThreadLocal = new ThreadLocal();public static final void prepare() {        if (sThreadLocal.get() != null) {            throw new RuntimeException("Only one Looper may be created per thread");        }        sThreadLocal.set(new Looper()); }


Looper private的构造器:

final MessageQueue mQueue;private Looper() {mQueue = new MessageQueue();mRun = true;mThread = Thread.currentThread();}

Looper初始化的时候,会初始化本线程对应的MessageQueue。


Lopper.loop()静态方法:

public static final void loop() {           Looper me = myLooper();           MessageQueue queue = me.mQueue;                           // Make sure the identity of this thread is that of the local process,           // and keep track of what that identity token actually is.           Binder.clearCallingIdentity();           final long ident = Binder.clearCallingIdentity();                           while (true) {               Message msg = queue.next(); // might block               //if (!me.mRun) {               //    break;               //}               if (msg != null) {                   if (msg.target == null) {                       // No target is a magic identifier for the quit message.                       return;                   }                   if (me.mLogging!= null) me.mLogging.println(                           ">>>>> Dispatching to " + msg.target + " "                       + msg.callback + ": " + msg.what                           );                   msg.target.dispatchMessage(msg);                   if (me.mLogging!= null) me.mLogging.println(                           "<<<<< Finished to    " + msg.target + " "                       + msg.callback);                                           // Make sure that during the course of dispatching the                   // identity of the thread wasn't corrupted.                   final long newIdent = Binder.clearCallingIdentity();                   if (ident != newIdent) {                       Log.wtf("Looper", "Thread identity changed from 0x"                           + Long.toHexString(ident) + " to 0x"                           + Long.toHexString(newIdent) + " while dispatching to "                           + msg.target.getClass().getName() + " "                           + msg.callback + " what=" + msg.what);                   }                                           msg.recycle();               }           }       }


msg.target是生成消息 的handler对象,表示需要处理这个消息的handler对象。Handler的void dispatchMessage(Message msg)方法见下节。

Looper可以通过静态方法getMainLooper()获取UI线程的Looper对象,通过静态方法myLooper(),获取本线程的Looper对象。

Handler

Handler负责对信息的发送和处理,工作线程可以引用UI线程的Handler实例对象,通过post、postDelayed和sendMessage方法,把消息发送到MessageQueue中。

其中post*方法,传递的为Runnable对象,Runnable对象被封装为Message的callback属性,所以最终发送到MessageQueue中的还是Message对象。

Handler通过覆复写handleMessage方法,作为处理Message的回调方法,实现对Message的处理。

消息处理步骤:

  • Looper在消费Message的时候,先判断Message中是否有callback方法,如果有,调用callback,处理消息。
  • 如果Handler中有mCallback方法,则调用该方法处理消息。
  • 否则,调用handleMessage方法处理消息。

一个线程可以有多个Handler对象,同一个Handler对象发送的Message,由对象自身的handleMessage方法进行处理。

handler.despatchMessage实例方法:

public void dispatchMessage(Message msg) {            if (msg.callback != null) {                handleCallback(msg);            } else {                if (mCallback != null) {                    if (mCallback.handleMessage(msg)) {                        return;                    }                }                handleMessage(msg);            }    }

在工作线程中,需要向UI线程发送消息是,不一定要在UI线程中建立Handler对象,并传递到工作现在。

在工作线程中,可以通过Looper.getMainLooper()获取到UI线程的Looper对象,并通过此Looper对象,实例化Handler对象,绑定到UI线程的Looper和MessageQueue。

class MyThread extends Thread{       public void run(){  Looper looper = Looper.getMainLooper(); //主线程的Looper对象  //这里以主线程的Looper对象创建了handler,  //所以,这个handler发送的Message会被传递给主线程的MessageQueue。  handler = new MyHandler(looper);  //构建Message对象  //第一个参数:是自己指定的message代号,方便在handler选择性地接收  //第二三个参数没有什么意义  //第四个参数需要封装的对象  Message msg = handler.obtainMessage(1,1,1,"其他线程发消息了");   handler.sendMessage(msg); //发送消息              }  } 

Message

Message是消息的载体,Message中有String arg1、String arg2、Object obj、int what等几个属性,用户传递简单参数。复杂参数则使用Bundle传递。

Message可以通过静态方法Message.obtain()和实例方法handler.obtainMessage()等方法获取,可以实现对Message对象的复用。通过实例方法message.cycle(),实现Message的回收复用。

实例方法message.sendToTarget()方法等同于实例方法handler.sendMessage()

MessageQueue

MessageQueue是和Looper一一关联的对象,通过消息队列机制对消息进行存储。




0 0
原创粉丝点击