Android的消息机制以及Message/MessageQueue/Handler/Looper

概览

* Message:消息。消息里面可包含简单数据、Object和Bundle,还可以包含一个Runnable(实际上可看做回调)。

* MessageQueue:消息队列,供Looper线程消费消息。

* Looper:用于循环处理Message,一个Thread结合一个Looper来实现消息循环处理。Android App的主线程包含了Looper。

* Handler:负责向当前Looper线程发送Message,并实现如何处理消息的回调,回调可放到Callback接口的实现中,也可以放在传递进去的Runnable中的run中。

消息处理流程

1. MainThread(一个Looper Thread)正在运行,线程中有MessageQueue可交互,并循环处理MessageQueue中的Message。

2. 在MainThread中创建一个Handler,handler与当前线程Looper的MessageQueue绑定。

3. 通过handler.sendMessage(Message msg)向MessageQueue发送消息,等候执行;通过handler.post(Runnable r)向MessageQueue发送一个空消息,该空消息附加了Runnable,等候执行。

4. MainThread轮询MessageQueue的Message,抛给Message对应的Handler执行。


Message

* 最好通过Message.obtain()来创建Message对象,从消息池里创建Message更高效。

源码分析

public final class Message implements Parcelable

{

public int what; // 用户定义的标识码

public int arg1; // 用来存储简单的数据,这样可以不使用Object/Bundle来做消息。

public int arg2;

public Object obj; // 对象型数据。

public Messenger replyTo;

Bundle data; // 复杂型消息数据

// Message的最终处理分两种情况:

Handler target; // 1)通过Message的target(Handler)处理消息,具体是Handelr实现handleMessage()。

Runnable callback; // 2)通过空消息的callback(Runnable)处理消息,具体是丢弃Message,然后直接调用run()。

private static final Object sPoolSync = new Object(); // 消息池用到的锁

private static Message sPool ; // 从消息池中取出的可用的消息对象。每取一次,这里就放置一个可用的。

private static int sPoolSize = 0; // 当前可用的消息对象数量

private static final int MAX_POOL_SIZE = 50 ;  // 池存放最大量

Message next; // 实现链表式消息池

// 从消息池中取一个可用的消息对象

public static Message obtain() {

synchronized (sPoolSync) {

if (sPool != null) {

Message m = sPool;

sPool = m.next;

m.next = null;

sPoolSize--;

return m;

}

}

return new Message();

}

// 从现有Message复制并返回

public static Message obtain(Message orig) {

Message m = obtain();

m.what = orig.what;

m.arg1 = orig.arg1;

m.arg2 = orig.arg2;

m.obj = orig.obj;

m.replyTo = orig.replyTo;

if (orig.data != null) {

m.data = new Bundle(orig.data);

}

m.target = orig.target;

m.callback = orig.callback;

return m;

}

// 发送消息

public void sendToTarget() {

target.sendMessage(this); // 调用的是 handler 的 sendMessage()

}

// 消息回收

public void recycle() {

clearForRecycle(); // 清除Message对象的所有信息

synchronized (sPoolSync) {

if(sPoolSize < MAX_POOL_SIZE){

next = sPool; // 下一个可用Message是当前sPool(可用)

sPool = this ; // 当前可用的Message为正在释放清除的Message对象

sPoolSize++; // 可用对象数量递增

}

}

}

}

MessageQueue

* holding the list of messages to be dispatched by a Looper。

* 不能直接向Looper的MessageQueue添加Message,需要通过Handler。

* 可通过 Looper.myQueue()获取到当前线程的MessageQueue。



Handler

* 创建一个Handler就会绑定到当前Thread/MessageQueue,之后,Handler可以向MessageQueue发送Message和Runnable,等候轮询执行。

* 发送一个Message:sendMessage(Message m)。

* 发送一个Runnable:post(Runnable r) 。

public class Handler

{

// 自定义的Handler必须实现该方法,用于处理消息

public void handleMessage(Message msg){}

// 或者指定一个实现了Callback接口的类

public interface Callback {

public boolean handleMessage(Message msg);

}

// 构造函数

// 默认情况下,handler会关联到当前Thread的Looper,如果没有Looper,抛异常

public Handler(Looper looper,Callback callback/*相当于指定了handleMessage()函数*/,boolean async){

mLooper=looper; mQueue=looper.mQueue; mCallback =callback;mAsynchronous = async;

}

public final Message obtainMessage(){ return Message.obtain(this); } // 直接调用的Message的obtain

// ---------------------------------------------------------------

// 发送消息到MessageQueue

// handler.sendXXX均调用此方法

public boolean sendMessageAtTime(Message msg,long uptimeMillis) {

MessageQueue queue = mQueue;

return enqueueMessage(queue,msg,uptimeMillis);

}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {

msg.target = this;

if (mAsynchronous) {msg.setAsynchronous(true);}

return queue.enqueueMessage(msg, uptimeMillis);

}

// ---------------------------------------------------------------

// 发送Runnable到MessageQueue

// 原理是把Runnable附加到一个空消息的callback上,当执行消息时,如果发现有callback,则执行callback。

public final boolean post(Runnable r) {

return sendMessageDelayed(getPostMessage(r),0);

}

private static getPostMessage(Runnable r,Object token) {

Message m = Message.obtain();

m.obj = token;

m.callback = r; // 指定Message的callback为r。通过sendMessage的消息没有callback,包含callback的Message将会被其callback执行。

return m;

}

// ---------------------------------------------------------------

// 处理消息

// 消息在Looper中是通过调用这个函数来实现处理消息的

public void dispatchMessage(Message msg) {

if(msg.callback!=null){ handleCallback(msg); } // 在Runnable中处理

else {

handleMessage(msg); // 调用Handler处理消息的函数

}

}

private static void handleCallback(Message message) {

message.callback.run(); //消息被丢弃,并且直接调用run(),而不是新开线程。

}

}// end handler()


Looper

 

* 默认线程并没有包含可以循环处理消息的功能,Looper类可以帮助线程实现消息循环。

 

public final class Looper

{

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); // 线程本地变量,每个线程一个Looper。

final Message mQueue;

final Thread mThread;

private Looper(boolean quitAllowed){

mQueue = new MessageQueue(quitAllowed);

mThread = Thread.currentThread();

}

// --------------------------------------------------------------------

// 准备。为当前线程创建一个Looper对象

static void prepare(boolean quitAllowed/*MessageQueue是否可退出*/) {

if(sThreadLocal.get()!=null){/*Exception,当前线程的Looper已存在,一个线程一个Looper*/}

sThreadLocal.set(new Looper(quitAllowed));

}

// --------------------------------------------------------------------

// 开始循环

public static void loop() {

final Looper me = myLooper();// 当前线程的Looper实例

final MessageQueue queue = me.mQueue;

for(;;){

Message msg = queue.next();

if(msg == null) { return;}

msg.target.dispatchMessage(msg); // 由Handler处理该消息

msg.recycle(); // 清理该消息,清空后返回消息池。

}//end for

}// end loop()

// --------------------------------------------------------------------

public void quit() { mQueue.quit(false); }

public boolean isIdling(){ return mQueue.isIdling();}

} // class end.


Demo

Demo#1 发送消息
class SomeActivity
{
  @Override
  public void onCreate(...){
  testMessage();
}

void testMessage(){
  MyHandler handler = new MyHandler();
  // or
  handler = new Handler(/*this.getMainLooper(),*/ new Handler.Callback(){ /*...*/ });

  // 发送Message
  Message m1 = new Message();
  m.setTarget(h);
  m.sendToTarget();

  // 发送Runnable(内部其实是发送了一个Message+Runnable)
  handler.post(new Runnable(){
    @Override
    public void run(){
      // 在主线程中运行
    }
  });
}

class MyHandler extends Handler{
  @Override
  public void handleMessage(Message msg){ /*...*/ }
}

Demo#2 自定义Looper线程
public static void testLooper()
{
  Thread tLooper = new Thread(new Runnable(){

  @Override
  public void run() {
    Looper.prepare();

    MyHandler h = new MyHandler();
    // 发送消息
    h.sendEmptyMessage(0);
    // 发送Runnable
    h.post(new Runnable(){
      @Override
      public void run() {
      Log.i("test","[in post runnable]threadid:"+Thread.currentThread().getId()); // tLooper线程ID
    }});

    Looper.loop(); // 一直循环。即使没有消息
  }});
  tLooper.start();
}


references

http://developer.android.com/reference/android/os/MessageQueue.html

http://developer.android.com/reference/android/os/Looper.html

Android的消息机制以及Message/MessageQueue/Handler/Looper,布布扣,bubuko.com

时间: 2024-10-10 13:28:55

Android的消息机制以及Message/MessageQueue/Handler/Looper的相关文章

【原创】源码角度分析Android的消息机制系列(五)——Looper的工作原理

ι 版权声明:本文为博主原创文章,未经博主允许不得转载. Looper在Android的消息机制中就是用来进行消息循环的.它会不停地循环,去MessageQueue中查看是否有新消息,如果有消息就立刻处理该消息,否则就一直等待. Looper中有一个属性: static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); 这也就解释了,前面我们所说的我们可以通过ThreadLocal实现Looper

Android 开发艺术探索——第十章 Android的消息机制

Android 开发艺术探索--第十章 Android的消息机制读书笔记 Handler并不是专门用于更新UI的,只是常被用来更新UI 概述 Android的消息机制主要值得就是Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑. MessageQueue即为消息队列,顾名思义,它的内部存储了一组消息,以队列的的形式对外提供插入和删除的工作.虽然叫队列,但内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息列表. Looper意思为循

【原创】源码角度分析Android的消息机制系列(一)——Android消息机制概述

ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 1.为什么需要Android的消息机制 因为Android系统不允许在子线程中去访问UI,即Android系统不允许在子线程中更新UI. 为什么不允许在子线程中更新UI呢?因为Android的控件不是线程安全的.既然是非线程安全的,那么若在多个子线程中并发访问,UI控制可能会处于一种不可预期的状态.有的读者可能会说,为什么不对UI控件加锁呢?加锁会降低UI访问的效率,因为加锁之后,若想要运行这段synchronized的代码,线程要先拿到

第10章 Android的消息机制

本章主要讲的内容是Android的消息机制. Android的消息机制主要是指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑.MessageQueue就是我们常说的消息队列,它的内部存储了一组消息,虽然叫做消息队列,但是它的内部却是采用单链表的数据结构才存储消息列表的.Looper为消息循环,由于MessageQueue只是一个消息的存储单元,它不能去处理消息,而Looper填补了这个功能,Looper会以无限循环的形式去查找是否有心得消息,

Android的消息机制之ThreadLocal的工作原理

提到消息机制大家应该都不陌生,在日常开发中不可避免地要涉及到这方面的内容.从开发的角度来说,Handler是Android消息机制的上层接口,这使得开发过程中只需要和Handler交互即可.Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行.很多人认为Handler的作用是更新UI,这说的的确没错,但是更新UI仅仅是Handler的一个特殊的使用场景,具体来说是这样的:有时候需要在子线程中进行耗时的IO操作,这可能是读取文件或者访问网络等,当耗时操作

Android的消息机制

1.背景                                                                Handler是Android消息机制的上层接口,通过handler可以轻松地将一个任务切换到Handler所在的线程中去执行. Handler的作用之一是更新UI,有时候需要在子线程中进行耗时的I/O操作,可能是读取文件或者访问网络等,当耗时操作完成以后可能需要在UI上做一些改变,这时用Handler. Android的消息机制主要是指Handler的运行机制

Android的消息机制Handler详解

Android的消息机制详解 Android的消息机制主要指 Handler 的运行机制,Handler的运行需要底层的MessageQueue 和 Looper 的支撑. MessageQueue:消息队列,它的内部存储了一组消息,以队列的形式对外提供插入和删除的工作,其内部存储结构采用单链表的数据结构来存储消息列表. Looper:可理解为消息循环. 由于MessageQueue只是一个消息存储单元,不能去处理消息,而Looper会以无限循环的形式去查找是否有新的消息,如果有的话就处理,否则

Android 中的消息模型(Message,MessageQueue,handle,looper)

Android 中的消息模型(Message,MessageQueue,handle,looper,) Android 中的消息通讯 1.Android 中线程的应用机制? 1)Android 中所有的耗时操作应在工作线程执行. 2)Android 中所有的UI操作应该在主线程(UI线程)执行. FAQ? 1)主线程执行执行耗时操作好吗? 不好,这样会阻塞UI操作. 2)工作执行完耗时操作,假如有数据要传递给主线程,那如何实现? 2.Android 中多线程应用时的消息模型? 使用Android

聊一聊Android的消息机制

侯 亮 1概述 在Android平台上,主要用到两种通信机制,即Binder机制和消息机制,前者用于跨进程通信,后者用于进程内部通信. 从技术实现上来说,消息机制还是比较简单的.从大的方面讲,不光是Android平台,各种平台的消息机制的原理基本上都是相近的,其中用到的主要概念大概有:1)消息发送者:2)消息队列:3)消息处理循环.示意图如下: 图中表达的基本意思是,消息发送者通过某种方式,将消息发送到某个消息队列里,同时还有一个消息处理循环,不断从消息队列里摘取消息,并进一步解析处理. 在An