Handler通信机制

目标:

1.Handler和Looper什么关系?

一个Looper对应一个MessageQueue,可以多个handler往MessageQueue发送消息。

2.一个线程有几个Handler?

3.Handler内存泄漏的原因?

4.使用Message时如何创建它?

5.子线程维护的Looper, 消息队列无消息时的处理方案是怎么样的?有什么用?

6.为什么主线程可以new Handler?如果想要在子线程new Handler,应该怎么办?

7.线程间通信原理是怎么样的?

8.Looper死循环为什么不会导致应用卡死?

9.既然可以存在多个Handler往MessageQueue中添加数据(发消息的各个Handler可能位于不用的线程),那么它内部是如何保证线程安全的?

一、Handler机制

1.1 Handler是什么?

Handler机制是Android提供的消息通信机制。

它涉及多个关键组件,包括Handler、Looper、MessageQueue和Message,共同协作以实现消息的发送、接收和处理。

Handler:负责发送消息和处理消息。当发出一个消息后,首先进入一个消息队列,发送消息的函数即刻返回,而另一个部分在消息队列中逐一将消息取出,然后对消息进行处理。这种机制通常用来处理相对耗时比较长的操作。
Looper:负责循环读取MessageQueue中的消息,读到消息之后就把消息交给Handler去处理。
MessageQueue:存储消息对象的队列。
Message:消息对象,是Handler机制中传递的基本单位。

1.2 Handler工作原理

Handler机制的工作流程大致如下:

1) 创建Handler:首先需要创建一个Handler对象,其构造函数中的参数如async和callback用于确定消息的处理方式。async参数确定用Handler发送的消息是否要设置成异步消息,而callback参数则允许在dispatchMessage回调时优先调用callback中的代码。
2)发送消息:通过调用Handler的sendMessage或post等方法发送消息到MessageQueue中。
3)处理消息:Looper循环读取MessageQueue中的消息,并将它们分发给相应的Handler进行处理。处理过程包括调用Handler的handleMessage方法(如果存在回调,则优先执行回调)。
Handler机制在Android开发中特别重要,因为它允许在主线程中更新UI,同时避免阻塞主线程。通过在子线程中执行耗时操作,并通过Handler将结果发送回主线程进行UI更新,可以实现线程间的有效通信和UI的平滑更新。

二、线程间内存共享

MessageQueue是线程间共享的消息容器,用于管理消息。

完成线程间通信的原理:内存共享,通过共享MessageQueue消息队列,实现主线程和子线程通信。

三、消息Message

3.1 消息排序

按照msg.updateTime进行排序,相对于系统开机时间的时间戳。

3.2 消息创建

消息创建采用享元模式,增加消息对象复用。

1)消息存在一个缓冲池sPool(大小为50个),缓存使用完的消息对象;

2)创建消息的时候,优先从sPool中拿取一个消息对象;

3)消息使用完成后,将消息字段重置,然后添加到sPool,用于复用。

四、Handler内存泄漏和解决方案

4.1 Handler内存泄漏的原因

内存泄漏原因:JVM回收的时候问题,根可达算法,被JVM GC Roots直接或者间接引用的对象不能够被回收。

Activity中,

Handler handler = new Handler();

handler是一个匿名内部类,持有Activity的this对象;

ActivityThread的

static sMainLooper: 是一个静态变量,作为GC Roots

static sThreadLocal->Looper-->MessageQueue-->Message-->Handler-->Activity

msg.target = this;(Handler)

采用delay发送的消息,引用链仍然存在。

4.2 解决内存泄漏的方法

打断引用链。

1.Handler声明为静态内部类对象,不持有Activity引用

2.Handler采用弱引用Activity对象

Looper执行的动力:线程提供的。

EventBus、Retrofit与主线程通信,都需要借助Handler

五、Handler如何正确创建

5.1 主线程

主线程为什么创建Handler不需要指定Looper?

Handler Handler = new Handler();

主线程main运行的时候,从主线程Looper.mainLooper()

5.2 子线程撞见

1)先创建Looper

创建以后,调用Looper.prepare()

Looper.prepare

2) 初始化Handler

3)Looper.loop()

5.3 子线程Handler  HandlerThread

封装了Handler

HandlerThread获取Looper

public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        boolean wasInterrupted = false;

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    wasInterrupted = true;
                }
            }
        }

        /*
         * We may need to restore the thread's interrupted flag, because it may
         * have been cleared above since we eat InterruptedExceptions
         */
        if (wasInterrupted) {
            Thread.currentThread().interrupt();
        }

        return mLooper;
    }

为什么需要采用while

因为如果是别的线程唤醒,如果Looper还没有初始化,需要继续等待Looper初始化。因此需要采用while。直到Looper有值。 

wait挂起:挂起线程,并且释放锁

sleep: 

六、Handler多线程安全

消息入列

消息获取:MessageQueue.next()  拿取一个消息

多个Handler往MessageQueue发送消息,如何保证线程安全性。

6.1 存消息的时候

boolean MessageQueue.enqueueMessage(Message msg, long when)

采用加锁的方式

synchronized (this) {

6.2 取消息的时候

Message MessageQueue.next()

synchronized (this) {

存消息和取消息的时候,同步进行。

6.3 Loop与ThreadLocal

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

Looper通过ThreadLocal进行缓存。

每个线程对应于自己的Looper。 

七、同步消息和异步消息

消息屏障:target==null的消息。保证异步消息优先执行(UI刷新优先)

异步消息:isAync=true是异步消息,用于UI刷新。view.scheduleTraversals

同步消息:

添加消息屏障:

postSyncBarrier: 插入一个消息屏障

removeSyncBarrier: 移除消息屏障

丢帧;

skip 30 frames!

八、Looper.loop死循环为什么不会发生ANR问题

等待和休眠

1)没有消息的时候,阻塞等待消息到来;

2)等待消息执行时间:没有到消息可执行时间,epoll机制进行超时等待。

8.1 epoll机制

涉及到I/O

select: 非租塞忙轮询方式。没有数据的会出现CPU空转,浪费资源。直到一系列I/O事件存在,但不知道是哪几个流存在事件。

epoll_wait: 有N个I/O事件,一个线程处理多个I/O事件。没有I/O事件的时候进行阻塞,

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Handler线程通信机制是指在多线程环境下,通过Handler进行线程间的通信和消息传递的机制Handler是Android中的一个类,它主要用于异步消息的处理和线程通信。当一个Handler被创建时,它会自动和当前线程的Looper对象进行绑定,从而使得该Handler可以接收和处理与该Looper关联的消息队列中的消息。 在线程间通信中,一般会涉及到两个关键的角色:发送者和接收者。发送者通过Handler将消息封装成Message对象,然后调用Handler的sendMessage()方法将消息发送到消息队列中。而接收者则通过Handler的handleMessage()方法来处理接收到的消息。 具体的线程通信流程如下: 1. 发送者线程创建一个Handler对象,并与自己的Looper进行绑定。 2. 发送者线程创建一个Message对象,并设置消息内容。 3. 发送者线程调用Handler的sendMessage()方法,将消息发送到消息队列中。 4. 接收者线程中的Looper会不断地从消息队列中取出消息,并交给接收者线程的Handler的handleMessage()方法进行处理。 5. 接收者线程的Handler处理完消息后,可以通过sendMessage()方法将结果发送给发送者线程或其他线程。 通过Handler线程通信机制,可以实现不同线程间的通信和协调。比如在子线程中进行耗时操作,然后将结果通过Handler回传到主线程进行UI更新等操作。 ### 回答2: 在Android开发中,Handler线程通信机制是一种用于在不同线程间进行通信机制。它可以将消息和任务发送到目标线程的消息队列中,然后在目标线程中执行这些消息和任务。 1. Handler的创建和使用: 首先,我们需要在目标线程中创建一个Handler对象。可以在主线程中创建Handler对象,并传入一个Looper对象作为参数。然后,我们可以通过调用Handler对象的post()、sendMessage()或其他类似方法,将消息或任务发送到目标线程的消息队列中。 2. 消息处理: 在目标线程中,Looper对象会不断地从消息队列中获取消息,然后根据消息的类型和内容进行处理。可以通过重写Handler类的handleMessage()方法来定义如何处理特定类型的消息。当有新消息到达时,Looper会调用这个方法来处理消息。 3. 线程通信: 通过使用Handler线程通信机制,我们可以在不同线程之间传递消息和任务。例如,我们可以在后台线程中执行耗时的计算,并使用Handler将计算结果发送到主线程,然后在主线程中更新UI界面。这样,我们就可以实现后台计算和UI更新的异步处理。 4. 消息队列和消息循环: Handler线程通信机制基于消息队列和消息循环的概念。消息队列是一个先进先出的数据结构,用于存储消息和任务。消息循环是一个不断循环的过程,在每次循环中,消息队列会被检查,如果队列中有消息,就会被取出并处理。 5. 线程安全: Handler线程通信机制是线程安全的,因为消息队列的访问是同步的。不同线程可以通过Handler对象将消息和任务发送到同一个消息队列中,这些消息和任务会被逐个处理,避免了多线程并发访问的问题。 总之,Handler线程通信机制是Android开发中一种常用的线程间通信机制,它可以将消息和任务发送到目标线程的消息队列中,然后在目标线程中处理这些消息和任务。它在后台计算和UI更新、线程安全等方面都具有重要的作用。 ### 回答3: Handler线程通信机制是Android中一种常见的线程间通信方式。Handler是Android中的一个类,它功能强大,可以用于创建一个与特定线程关联的消息队列,从而实现线程间的通信。 在使用Handler线程通信机制时,一般分为两个角色:发送消息的线程和接收消息的线程。发送消息的线程使用Handler对象发送消息,而接收消息的线程则通过重载Handler类的handleMessage()方法来处理接收到的消息。发送消息的线程将消息封装成Message对象,然后通过Handler的sendMessage()方法将消息发送给接收消息的线程。接收消息的线程在handleMessage()方法中根据消息的种类来处理相应的任务。 Handler线程通信机制的实现主要有以下几个步骤: 1. 创建Handler对象:在接收消息的线程中创建一个Handler对象,用于接收和处理消息。 2. 发送消息:在发送消息的线程中,通过Handler对象的sendMessage()方法将消息发送给接收消息的线程。消息可以通过Message类来创建,并且可以通过Message的arg1、arg2和obj属性来传递一些额外的数据。 3. 处理消息:接收消息的线程需要重载Handler类的handleMessage()方法,该方法用于处理接收到的消息。根据消息的种类,可以使用switch语句来处理不同的消息类型。 4. 更新UI:如果接收消息的线程和UI线程需要进行通信,可以在handleMessage()方法中更新UI相关的内容。可以使用post()方法或者runOnUiThread()方法来在UI线程中更新UI。 5. 销毁Handler:在不需要使用Handler对象的时候,应该调用Handler的removeCallbacksAndMessages()方法取消消息的发送,并且释放相关资源。 通过Handler线程通信机制,可以实现不同线程之间的通信和协作,提高应用程序的灵活性和响应性。它是Android开发中常用的一种线程间通信方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值