美文网首页
Android Handler线程间通信原理分析

Android Handler线程间通信原理分析

作者: Gray_s | 来源:发表于2021-03-01 03:19 被阅读0次

Android的Handler线程间通信作为面试必问,重要性不言而喻。作为开发者如何理解和利用进程间通信就变得尤为关键。本文将分三个部分剖析:使用方式、原理分析,如何利用。

使用方式

Handler的使用方式很简单

  • 处理消息
//处理接受到的message
    var handler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {

        }
    }
//或
    var handler1 = Handler(Looper.getMainLooper(), object : Handler.Callback {
        override fun handleMessage(msg: Message): Boolean {
            return true
        }

    })

代码中可以看到主要有两种方式,一种是重写handleMessage()方法,一种是实现Handler.Callback接口。这两种方式在优先级上有所不同,当实现Handler.callback接口时将优先执行接口的方法,当返回flase时才会执行重写的handleMessage()方法。两种方式中共有的参数,是表明使用的时哪个线程的Looper,最后就会在哪个线程执行方法。

  • 发送消息
        val obtainMessage = handler.obtainMessage()
        //  设置传入的数据
        obtainMessage.what = 1
        handler.sendMessage(obtainMessage)
//或
        handler.post(object : Runnable {
            override fun run() {
            }
        })

发送消息同样有两种方式,一种是获取message,传入数据然后发送,还有一种是直接post传入一个Runnable对象。就这两种方式而言,本质是一样的,第二种方式依然会转换成一个Message对象。但区别在于,如果handle重写了handleMessage()方法或者实现了Handler.Callback接口,那么将不会执行,只会执行postrun()方法。

原理分析

组成部分

从使用的代码来看,线程间通信功能的实现至少有:

  • Handler
    用于处理消息的
  • Looper
    循环,用于分发消息
  • Message
    消息的载体

但是只有以上的组件,并不能完成这个功能。从逻辑上来看:1、线程2的Looper分发线程1Messagehandler中去处理。2、在handler发送线程1的Message。在这两条逻辑上似乎缺少东西联系在一起。Looper从哪里获取到Message,handlerMessage发送到哪里去。这时就需要第4个组件:

  • MessageQueue
    存储Message,由Looper获取
    所以整个的通信流程如图所示
线程间通信流程

具体实现

以主线程为例,在我们的App启动时最先执行的时启动Looper

//android.app.ActivityThread#main
        Looper.prepareMainLooper();
        ...
        ActivityThread thread = new ActivityThread();
        ...

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        ...
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");

上面就是启动Loop的主要方法,同时会创建ActivityThread对象,在这个对象中就有Handler对象。

代码中的prepareMainLooper()是一个关键代码。

 public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

这段代码会先判断是否已有主线程的Loop,没有则会通过myLooper()创建所在线程的Looper,然年后再把Loop赋值给静态变量sMainLooper ,通过这个静态变量就可以跨线程获取主线程的Looper。而myLooper()只能获取当前线程的方法。原因就在于prepare(),和ThreadLocal对象。

    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");
        }
        //  把当前线程创建的Looper放入ThreadLocal中
        //  这个类提供线程局部变量。 这些变量与其正常的对应方式不同,因为访问一个的每个线程
        //(通过其get或set方法)都有自己独立初始化的变量副本
        sThreadLocal.set(new Looper(quitAllowed));
    }

Handle中主要的方法为handleMessage()dispatchMessage()以及各种发送message方法。

    public void handleMessage(@NonNull Message msg) {
    }
    
    //表明 了消息处理的顺序
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

MessageQueue中主要有5类方法

  • 创建MessageQueue
    nativeInit() Native方法
  • 添加Message进入队列
    enqueueMessage()
  • Message出队列
    next()
  • 删除队列中的Message
    removeMessage()
  • 销毁整个队列
    __nativeDestroy()__Native方法
    这些方法表面MessageQueue是一个容器用来存放Message。
    而Message对象,就是用来存放传递数据的容器。
    以上是4个组成部分主要的实现方式

组件间关系

知道了组件间的实现,那么组件间的是怎么调用的?
依然从使用来看,首先handler要求传入Looper对象,handler会获取Message对象。所以我们会认为,handler持有Message、Looper对象。但当我MessageQueue对象却无法直接看到。从前面的分析中可以知道,MessageQueue是容器,Looper分发Message,所以Handler持有MessageQueue对象才更为合理,而Looper同样也应该持有MessageQueue对象,才能从其中获取、分发Message,Message同样应持有Handler对象,这个Looper才能知道该把Message发给哪里的Handler。
在查看源码后确实如此(为了方便就不放出源码)


关系图

如何利用

首先,线程间通信的主要功能就是跨线程。其次,在实现上来说,会利用到队列。针对这两个特点,我们可以加以利用。例如,高频发送的命令式异步任务,这个任务需,高频的发送命令,同时命令会有延时操作,而且新的命令会覆盖到已经进入队列但暂为执行的任务。这样的任务就适合直接利用Handler的结构进行解决,而不用自己维护一个队列。

相关文章

  • Handler 的工作原理

    参考资料gityuan 一、Handler原理 Handler 是 Android 中线程间通信的组件。在异步线程...

  • Android系统Java源码探索(5)—Binder通信机制

    一 前言 之前分析了Android系统线程间的通信机制(Handler),这篇看看Android系统进程间的通信—...

  • Android Handler线程间通信原理分析

    Android的Handler线程间通信作为面试必问,重要性不言而喻。作为开发者如何理解和利用进程间通信就变得尤为...

  • Handler 源码分析

    Handler原理解析 Handler做为Android线程间通信的基础,是开发与面试必备技能。与之相关的有Asy...

  • handler全家桶

    handler是android中实现线程之间通信的方式之一,他的原理值得我们了解。 handler的通信实现原理离...

  • Android Handler 原理分析

    Android Handler 的原理分析 Handler 是安卓中最常用的组件。作用就是 线程间的消息通知 但...

  • 撸Handler-Message-MessageQueue-Lo

    Handler-MessageQueue-Looper是Android特有的线程间通信机制。 Handler Ha...

  • 面试题

    handler实现原理,activity启动原理,进程通信原理,多线程等等, 4、android的方向也很多,高级...

  • Handler消息机制和ThreadLocal原理

    一、简介 Handler作为Android线程间通信的常用方式,主要由Handler、Looper、Message...

  • Handler知识点汇总

    Handler说明: Android开发中可以使用Handler发送消息进行线程间的通信。Handler发送并处理...

网友评论

      本文标题:Android Handler线程间通信原理分析

      本文链接:https://www.haomeiwen.com/subject/hgsgfltx.html