Looper、Message、Handler和HandlerThread之间的关系

版权声明:转载请注明出处 https://blog.csdn.net/QasimCyrus/article/details/51830575

Android中,使用AsyncTask来执行简单的后台线程,但是AsyncTask较适用于短暂的、不重复的运行任务。因为从Android3.2起,AsyncTask不再为每个实例创建线程,而是利用一个Executor在单一的后台线程上运行所有的AsyncTask后台任务,相当于所有的AsyncTask实例在同一个队列中排队运行,所以长时间且重复运行的AsyncTask会影响其他实例的运行,导致堵塞。实现按需下载的等后台运行方式,通常会使用到HandlerThread。

消息

首先介绍一下消息(Message),消息是Message类的实例,携带着需要处理的各种任务信息。有以下几个常见变量:

  1. what:用户定义的int型消息代码,用来描述和识别信息;
  2. obj:随消息发送的用户指定对象;
  3. target:处理消息的Handler,创建Message时会自动与一个Handler关联,通常不用手动设置;
  4. arg1、arg2:随消息返回的两个int类型参数。

Handler

Handler作为Message的目标,除了用来触发message的处理事件,也是创建和发布Message的接口。message是在Handler.handleMessage(...)方法中进行处理的。


Looper和Message、Handler的关系

Android的消息循环(message loop)由线程和looper组成。Looper对象管理着消息队列(meesage queue),消息队列中存放着许多的消息(message),它们与handler相关联。为了与Looper协同工作,Handler总是引用着Looper。 主进程本身就是一个拥有handler和Looper的消息循环,在主线程中Android 默认已经调用了Looper.prepare()方法,调用该方法的目的是在Looper 中创建MessageQueue成员变量并把Looper对象绑定到当前线程中。
  • 一个Message只和一个目标Handler相关联,但是多个Message能引用同一个目标Handler。(如下图左)
  • 一个Handler只和一个Looper相关联,但是多个Handler可以与一个Looper相关联。所以消息队列中可能存放着来自不同Handler的Message。(如下图右)
          

创建Message并关联Handler

如果有一个类继承了HandlerThread,那么Handler可以在函数onLooperPrepared()中新建,因为该函数是在Looper首次检查消息队列之前调用的。一般会在new一个Handler的同时覆写其handleMessage(...)方法。
Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                //TODO
            }
        }
    };

消息的发送可以有以下几种:

  • 使用Handler.obtainMessage(...)方法来创建信息,此时可以将消息自动设置目标为该Handler对象,取得Message之后可以使用sendToTarget发送给Handler。Handler会把该Message放置在MessageQueue消息队列尾部
Message mMessage = mHandler.obtainMessage(...);
mMessage.sendToTarget();

  • 使用Handler.sendMessage(...)方法:
mHandler.sendMessage(message);

  • 也可以使用Handler.post()方式来发送消息:
mHandler.post(new Runnable() {
            @Override
            public void run() {
                //TODO
            }
        });
看看源码会发现它是把Runnable转换成了一条空的message,设置它的私有变量callback为我们传入的Runnable,然后再调用sendMessageDelayed(...)方法的。
当message设有回调方法时,它从消息队列取出后,是不会发给target Handler的,而是直接执行存储在callback中的Runnable的run()方法。


          

猜你喜欢

转载自blog.csdn.net/QasimCyrus/article/details/51830575