Android异步相关源码详细分析(Handler、Message、Looper、MessageQueue)

本文深入探讨了Android中异步处理的重要概念,包括Handler、Message、MessageQueue和Looper的工作原理及其源码分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 前言

  • 详细介绍Android异步处理以及相关的HandlerMessageMessageQueueLooper等源码分析。
  • 本文略长,源码分析较多,请多注意代码中的注解。
  • 本文资料来源网络公开资源,并根据个人实践见解纯手打整理,如有错误请随时指出。
  • 本文主要用于个人积累及分享,文中可能引用其他技术大牛文章(仅引用链接不转载),如有侵权请告知必妥善处理。

2. 异步、UI主线程

2.1. 异步

  • 多数情况下,耗时操作均应在子线程执行,在UI主线程处理结果或操作UI对象展示结果等,这就是Android常见的异步模式;
  • 如果直接在UI主线程处理耗时操作,将导致UI线程的阻塞,报错ANRapplication not responding);
  • 如果在子线程处理耗时操作,同时又在子线程操作UI对象,这同样是android系统所不允许的,将导致CalledFromWrongThreadException

2.2. UI主线程的同步和不安全性

  • app启动时,系统会为它创建一个进程,并创建一个UI主线程,这个主线程将一直存在直到该app退出并销毁。Android中所有的涉及UI的操作,都必须在UI主线程操作。UI主线程更新UI时,最终调用的是invalidate()方法,而这个方法是线程不安全的,故UI主线程也是不安全的。
  • 你可以把这种状态理解为刷新方法invalidate()没有同步锁,如果Android不限制必须在UI主线程操作UI对象,这时在多个子线程对同一UI对象进行修改,将导致多次UI对象的刷新,并且不保证中间某一和最终刷新结果符合预期。故Android对操作UI的限制,可以保证UI线程的操作同步。

3. 消息处理机制HandlerMessageMessageQueueLooper

3.1. 形象释义

在这里为便于理解,我可以先简单地将把它们的关系形象化到一个虚构的邮政业务中(做初步的了解用,后面会有更加详细的分析)。可以想象出一个这样的世界,他们的世界很小,只有一个邮局,所有的邮件、信件业务都由这个邮局承担,并且每个人都是聋子和哑巴,只能通过邮局传递消息:

  • Handler
    Handler可以理解为一个的装置,邮政局发件窗口就是的装置,收件窗口就是的装置,某人通过发件窗口发邮件到其他人或者政府单位,其他人或者政府单位通过收件窗口收取邮件
  • Message
    Message就是邮件,这个邮件可以是一张明信片、信件,也可以是衣服、食物、杂物的包裹,由发件窗口发出,将来会由收件窗口接收
  • MessageQueue
    MessageQueue可以理解为邮政局的仓库,这里每天都会有来自发件窗口新的邮件自动加入,又有邮件被邮递员检出
  • Looper
    Looper可以理解为专门检出和发信的邮递员,他会不断的从仓库MessageQueue中检出信件,并放到收件窗口

在这个例子中每个人,可以看做是一个子线程,而这个世界的统一政府可以看做是UI主线程,邮局就是这么一套消息处理机制。

3.2. 专业释义

  • Handler
    HandlerMessage实例发送到MessageQueue中,并消息机制处理后的Looper分发给它的Message实例
  • Message
    是线程间通讯的消息载体(?持疑,请看 3.3.2.2. 第2条MessageQueueenqueueMessage(...)方法的源码分析)
  • MessageQueue
    是承载Message的队列(?持疑,请看 3.3.2.2. 第2条MessageQueueenqueueMessage(...)方法的源码分析),每个线程只有一个MessageQueue,并由唯一的Looper管理,遵循先进先出原则,Looper无限循环获取其中的Message,如没有MessageLooper将暂时阻塞
  • Looper
    被线程创建并且每个线程只有一个Looper,管理MessageQueue,并通过Looper.loop()方法中循环获取MssageQueue中得msg,然后msg.target.dispatchMessage(msg)发送msg给对应的Handler实例(msg.target在消息处理过程中被赋值为发送这条msgHandler的实例)

3.3. 源码分析

3.3.1. 示例

注意,这里有2种写法,主要是创建Handler时所在的线程不同,但本质是相同的。后面会有详细说明。

public class MainAsyncActivityA extends AppCompatActivity {
    @Bind(R.id.execute_btn)
    protected Button execute_btn;
    @Bind(R.id.show_tv)
    protected TextView show_tv;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_async_act_a);
        ButterKnife.bind(this);

        execute_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                thread01.start();
                //thread02.start();
            }
        });
    }
//-------------------------------------第1种写法------------------------------
    Thread thread01 = new Thread(new Runnable() {
        @Override
        public void run() {
            //假设这里做了耗时操作......
            String resultStr = "子线程01的处理结果";

            //创建Message
            Message message = Message.obtain();
            message.obj = resultStr;

            //Handler的实例handler01负责发送消息
            handler01.sendMessage(message);
        }
    });

    //在主线程创建Handler
    Handler handler01 = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //接收消息
            show_tv.setText(msg.obj.toString());
        }
    };

//-------------------------------------第2种写法------------------------------
    Thread thread02 = new Thread(new Runnable() {
    @Override
    public void run() {
        //假设这里做了耗时操作......
        String resultStr = "子线程01的处理结果";

        //创建Message
        Message message = Message.obtain();
        message.obj = resultStr;

        //获取主线程的Looper实例
        Looper looper = Looper.getMainLooper();
        //在子线程创建Handler,传入主线程的Looper实例,则此Handler的接收者即为指定的主线程
        Handler handler = new Handler(looper){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                Logger.d("handler01-handleMessage()");
                show_tv.setText(msg.obj.toString());
            }
        };

        //Handler的实例handler01负责发送消息
        handler.sendMessage(message);
    }
});

}
3.3.2. 源码分析

主要分析HandlerMessageQueueLooper被创建 —> handler01.sendMessage(message)发出消息 —> super.handleMessage(msg)接收消息这中间的过程。

3.3.2.1. HandlerMessageQueueLooper创建过程
  • 第1种写法,在UI主线程创建Handler实例

    1. Handler实例在Activity中被创建,即在UI主线程被创建,而UI主线程实际是由ActivityThread类管理的。当一个Acttivityattach(附着\绑定)在window的时候,ActivityThread实例同时被传入当前Activity,用于管理Activity的主线程操作,如下源码片段:

      public class Activity extends ContextThemeWrapper implements ...... {
      
          ......
      
          final void attach(Context context, ActivityThread aThread,
              Instrumentation instr, IBinder token, int ident,
              Application application, Intent intent, ActivityInfo info,
              CharSequence title, Activity parent, String id,
              NonConfigurationInstances lastNonConfigurationInstances,
              Configuration config, String referrer, IVoiceInteractor voiceInteractor,
              Window window) {
      
          ......
      
          //ActivityThread aThread赋值给mMainThread
          mMainThread = aThread;
      
          ......
      }
    2. ActivityThread在app启动时被创建,并调用了Looper类中的prepareMainLooper()来创建一个唯一的主线程Looper实例,如下代码片段:

      //ActivityThread.java中的main入口方法,启动了主线程的Looper
      
      public static void main(String[] args) {
          ......
      
          //调用了主线程专用的prepareMainLooper()
          Looper.prepareMainLooper();
      
          ......
      
          //调用了loop()启动looper功能
          Looper.loop();
      
          ......
      }
      //Looper.java中,看prepareMainLooper()方法的注释即可明白
      
      /**
       * Initialize the current thread as a looper, marking it as an
       * application's main looper. The main looper for your application
       * is created by the Android environment, so you should never need
       * to call this function yourself.  See also: {@link #prepare()}
       */
      public static void prepareMainLooper() {
          prepare(false);
          synchronized (Looper.class) {
              if (sMainLooper != null) {
                  throw new IllegalStateException("The main Looper has already been prepared.");
              }
              sMainLooper = myLooper();
          }
      }
    3. UI主线程 Looper被创建(prepareMainLooper())时,调用了Looperprepare(false),在prepare中,new了一个Looper并放入ThreadLocal<Looper> sThreadLocal中,如下片段:

      //Looper.java中
      
      /** Initialize the current thread as a looper.
        * This gives you a chance to create handlers that then reference
        * this looper, before actually starting the loop. Be sure to call
        * {@link #loop()} after calling this method, and end it by calling
        * {@link #quit()}.
        */
      public static void prepare() {
          prepare(true);
      }
      
      private static void prepare(boolean quitAllowed) {
          if (sThreadLocal.get() != null) {
              throw new RuntimeException("Only one Looper may be created per thread");
          }
          //这行是关键代码
          sThreadLocal.set(new Looper(quitAllowed));
      }
    4. new Looper的过程中,创建了一个MessageQueue的实例,并持有它

      //Looper.java中
      
      private Looper(boolean quitAllowed) {
          mQueue = new MessageQueue(quitAllowed);
          mThread = Thread.currentThread();
      }
    5. 最后,创建Handler时,Handler构造函数中会调用Looper.myLooper()获取当前线程(UI主线程)的Looper实例,并赋值给Handler的属性mLooper,同时,获取了已创建的mLooper.mQueue赋值给HandlermQueue,持有以备使用。

      //Handler.java中
      
      ......
      
      public Handler(Callback callback, boolean async) {
      
          ......
      
          mLooper = Looper.myLooper();
          if (mLooper == null) {
              throw new RuntimeException(
                  "Can't create handler inside thread that has not called Looper.prepare()");
          }
          mQueue = mLooper.mQueue;
          mCallback = callback;
          mAsynchronous = async;
      }
      
      ......
      
  • 第2种写法,在子线程创建属于UI主线程Handler实例
    通过调用Looper.getMainLooper(),获取的即为ActivityThread所创建的主线程Looper实例sMainLooper,然后将这个looper传入Handler构造函数中,同样会赋值给Handler的属性mLooper,同时,获取了已创建的mLooper.mQueue赋值给HandlermQueue,持有以备使用。

    //Handler.java中
    
    ......
    
    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
    
    ......
    
3.3.2.2. Handler发出消息 –> 接收消息

下面来了解下Handler发出消息 –> 接收消息中间的详细过程。因为上文中有两种写法,并这两种写法本质相同,就以第1种写法讲解了。

  • 发出消息,handler01.sendMessage(message),进入Handler类可以看到,最终调用的是HandlerenqueueMessage(...)方法,而HandlerenqueueMessage(...)方法最终调用的是MessageQueue的enqueueMessage(...)方法,并给msg.target赋值当前Handler的实例,如下片段:

    //Handler.java中
    
    ......
    
    public final boolean sendMessage(Message msg) {
        return sendMessageDelayed(msg, 0);
    }
    
    ......
    
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //这里的MessageQueue实例来源于looper的属性
        //(创建Looper实例时被创建的MessageQueue实例)
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        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);
    }
    
    ......
    
  • 调用MessageQueueenqueueMessage(...)方法,是MessageQueue队列添加Message实例的过程,略复杂,包含了消息队列的排队原理,很重要,请看下面代码片段和中文注解将详细分析:

    //MessageQueue.java中
    ......
    
    boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }
    
        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }
    
            msg.markInUse();
            msg.when = when;
    
            //将属性mMessages赋值给新的Message p,多数情况下为null
            Message p = mMessages;
            boolean needWake;
    
            // 这里开始区分2种情况:
    
            // 1,是队列中无任何msg或者队列中的msg(或Message链)
            // 有被指定的发送时间,而这个时间大于新的msg,则给新的msg的
            // next(是一个Message)赋值为队列中原有的msg(或Message链)
            // ,将生成的新的msg链(包含了next中的原有的msg或msg链)
            // 赋值给mMessages属性。
    
            // 2,是如果队列中有之前的msg(或Message链)滞留在队列的头部
            // 没有发出,如某msg指定了发送时间when而时间未到滞留
            // 在队列中,那么就需要将最新添加进来的msg添加到即刻
            // 发出的时间最近的(when < 新msg的when)原有的msg的next中,
            // 将原有的msg链中非即刻发出的还需要滞留在队列中的msg
            //(或Message链),添加在最新添加进来的msg的next中,相当于
            // 重新排序了一下。
    
            if (p == null || when == 0 || when < p.when) {
                //第1种情况:
                // 无任何msg或者队列中的msg(或Message链)有被指定的发送时间,而这个时间大于新的msg
                // 新的msg的next(Message)赋值为原有的msg,形成新的消息链
                msg.next = p;
                // 再将MessageQueue的属性mMessages赋值为新的msg
                mMessages = msg;
                needWake = mBlocked;
            } else {
                //第2种情况:
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
    
                //队列中有msg(或Message链),链中第1个msg的when已经过
                //上面的判断必小于新的msg,则这个第1个msg还排在第1位
                //循环找到when大于新msg.when的那个消息(或为null)为止,
                //将新的msg的next设置为找到的这个msg(包含它的链),
                //也就是将新的msg添加在整个队列中“即刻将发出”(when比新msg小的)
                //的msg的后面,而“非即刻将发出”(when比新msg大的)
                //或是为null的msg(或Message链)则排在新msg的后面,形成这么一个新的消息链
                for (;;) {
                    //第1个msg还排在第1位
                    prev = p;
                    //原有的第2或第n个msg
                    p = p.next;
    
                    //找到when大于新msg.when的那个消息(或为null)为止
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                //最后“非即刻将发出”(when比新msg大的)或是
                //为null的msg(或Message链),排在新msg后面
                msg.next = p; // invariant: p == prev.next
                //新msg排在“即刻将发出”(when比新msg小的)的msg(或Message链)的后面
                prev.next = msg;
            }
    
            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }
    ......
    1. 在这段代码中,我们可以发现,Message这个类并不像所想象的或之前了解的那么单纯,它承担了消息队列形成一个链条的关键作用,主要通过其next属性(next的类型就是Message)构建消息队列中消息的排队。
    2. 反而是MessageQueue并没有发现它存在承担队列这个“实体”作用的代码,所以可以认为,Message是一个队列链条的“实际承担者”(如,排队买票,队伍里的人和队伍本身),而MessageQueue则是对Message队列链条做 排队整理被取用 等的操作类(如,队伍排队现场秩序的指挥员)。
  • 消息已准备好了,那么一直在运行的looper将怎么处理消息呢,请看Looper.loop(),由于主线程ActivityThread.java中已启用了LooperLooper.loop()方法),在msg已加入MessageQueue队列的情况下,looper在不停的循环获取其中的消息,并分发给接收者handler实例,我们看一下Looper检出和分发功能的loop()方法源码:

    //Looper.java中
    ......
    
     /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
    
        //获取当前looper
        final Looper me = myLooper();
    
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
    
        //获取之前创建Looper时,创建的MessageQueue实例
        final 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();
    
        //循环获取队列中消息
        for (;;) {
    
            //queue.next()返回一条消息,其中其实是从msg链中取
            //第1位的msg,也是无限循环的获取过程,
            //要么返回null,要么返回一个即刻需要发送的
            //或指定时间已到的排第一位的msg
            Message msg = queue.next(); // might block
    
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
    
            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
    
            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
    
                //这里就是最终的分发消息的调用,这里的msg.target
                //即绑定的handler,前面有提到
                //Handler的enqueueMessage(...)方法中,
                //给msg.target赋值当前Handler实例
                msg.target.dispatchMessage(msg);
    
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
    
            if (logging != null) {
                logging.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(TAG, "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.recycleUnchecked();
        }
    }
    ......
  • loop到需要发送的msg后,调用msg.target.dispatchMessage(msg),又回到了Handler中,最终调用了HandlerhandleMessage(Message msg)方法,这样消息就给到了你定义的Handler实例中重写的handleMessage(...){}中,的如下代码片段:

    //Handler.java中
    .......
    
    /**
     * Subclasses must implement this to receive messages.
     */
    public void handleMessage(Message msg) {
    
    }
    
    /**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
    
    .......

3.4. 其他写法

创建Handler时,传入Callback,消息机制和上面的没有区别,只是接收消息多了一个方式(Callback的handleMessage):

    Handler handler03 = new Handler(Looper.getMainLooper(), new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            //如果这里为false,下面Handler的handleMessage将同样收到消息;
            //如果返回true,则Handler的handleMessage不会收到消息
            return false;
        }
    })
    //下面是Handler的handleMessage
    {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Logger.d("handler03-handleMessage()");
        }
    };

3.5. 子线程之间的消息传递

原理同子线程到主线程的消息传递相同。
简单描述下:如子线程A发送消息给子线程B,子线程A中只要持有子线程B的Looper创建的Handler实例,就可以正常调用handler.sendMessage(message)发送消息到子线程B,子线程B将在Handler中接收消息并执行需要的任务。这种情况下,在子线程B中就必须在run开头主动调用Looper.prepare(),中间代码创建Handler用于接收消息,以及在run结尾调用Looper.loop()启动looper,同时,在任务彻底完成后,需要主动调用looper.quit()退出looper任务,则是当前子线程B将会自动销毁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值