惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Troy Hunt's Blog
F
Fortinet All Blogs
D
DataBreaches.Net
Google DeepMind News
Google DeepMind News
Y
Y Combinator Blog
The Register - Security
The Register - Security
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
V
Vulnerabilities – Threatpost
S
Securelist
S
SegmentFault 最新的问题
T
Threat Research - Cisco Blogs
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Privacy International News Feed
S
Schneier on Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
GbyAI
GbyAI
Apple Machine Learning Research
Apple Machine Learning Research
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
美团技术团队
Cyberwarzone
Cyberwarzone
C
Cisco Blogs
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google Online Security Blog
Google Online Security Blog
M
MIT News - Artificial intelligence
U
Unit 42
V
V2EX
C
CERT Recently Published Vulnerability Notes
云风的 BLOG
云风的 BLOG
B
Blog
博客园 - 叶小钗
Attack and Defense Labs
Attack and Defense Labs
Security Archives - TechRepublic
Security Archives - TechRepublic
aimingoo的专栏
aimingoo的专栏
Hacker News: Ask HN
Hacker News: Ask HN
博客园 - Franky
Engineering at Meta
Engineering at Meta
Schneier on Security
Schneier on Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Blog of Author Tim Ferriss
IT之家
IT之家
W
WeLiveSecurity
Cisco Talos Blog
Cisco Talos Blog
K
Kaspersky official blog
Martin Fowler
Martin Fowler
SecWiki News
SecWiki News

博客园 - cacard

Android中的内部类引起的内存泄露 ArrayList/Vector的原理、线程安全和迭代Fail-Fast JVM中的Stack和Frame JVM中的垃圾收集算法和Heap分区简记 无锁编程以及CAS 简述Java内存模型的由来、概念及语义 MQTT协议简记 RabbitMQ的工作队列和路由 RabbitMQ 入门 [Java] LinkedHashMap 源码简要分析 [Java] HashMap 源码简要分析 [Java] Hashtable 源码简要分析 CentOS 安装 Hadoop 手记 树莓派(RespberryPi)安装手记 RPC简述 [C++] const与重载 [C++] 左值、右值、右值引用 [C++] 引用 Java线程池 / Executor / Callable / Future
Android的消息机制: Message/MessageQueue/Handler/Looper
cacard · 2014-07-01 · via 博客园 - cacard

概览

* 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类可以帮助线程实现消息循环。

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#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();
}