前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >音视频直播--深度理解Handler 与 HandlerThread

音视频直播--深度理解Handler 与 HandlerThread

作者头像
音视频_李超
发布2020-04-01 20:44:40
8140
发布2020-04-01 20:44:40
举报
文章被收录于专栏:音视频直播技术专家

前言

大家好,今天我为大家讲解一下Android系统下的Handler机制。做过Android系统开发的人都清楚,App应用程序的主线程是决对不能被阻塞的,因为它的主线程就是UI线程。一旦它被阻塞了,用户会感觉APP卡死似的,基本就没法使用了。所以在音视频直播项目中,我们对摄像头的控制,视频画面的渲染都要放在子线程中进行。下面我们就来详细的剖析一下Android系统下的Handler和HandlerThread机制。

常用线程模型

给大家详细介绍handler和handlerthread之前,先给大家讲一下我们在实际工作中都是如何使用线程的。实际工作使用线程时,最大的难点是线程之间通信问题。 线程之间通信有很多方法,如信号量、 管道、 共享内存、共享文件、 消息队列等。 这些方法中用的最多的还是消息队列,围绕着消息队列我们一般有两种线程模型:

第一、创建一个新线程,然后从消息队列中取出一个任务,执行这个任务,完成任务后线程结束。这种模型非常的简单,我称之为“用后即焚” 。但这种模型效率很差,尤其是频烦的开关线程会消耗大量CPU资源。解决办法是创建一个线程池,每次从线程池中获取新线程,当线程执行完任务后将线程放回线程池以便线程的重复利用。

线程模型一

第二、创建一个新的线程,在该线程中执行一个死循环函数,不停的从消息队列中取出消息进行处理。

线程模型一

在Android中的Handler与HandlerThread就是用的第二种线程模型

MessageQueue

MessageQueue非常简单,它就是一个队列,两个重要方法,一个是enqueueMessage方法,该方法用于将Message类型消息存放MessageQueue中,另一个方法是next,用于从MessageQueue中取消息。

什么是Looper

Looper是一个消息分发器,它的作用是从消息队列中取出消息,然后做消息分发。我们看一下它是如何实现的。

注意,它与线程和Queue是一对一的关系,并且它是绑定某个具体线程内运行的。

在Looper类中定义了两个重要的成员mQueue和mThread,分别指向消息队列和线程。代码如下:

代码语言:javascript
复制
public final class Looper {
    ......
    final MessageQueue mQueue;  //指向要处理的消息队列
    final Thread mThread;       //对就在的线程
    ......
}

另外,该类中最重要方法是 loop 函数,我们看一下它是如何实现的:

代码语言:javascript
复制
/**
 * Run the message queue in this thread. Be sure to call
 * {@link #quit()} to end the loop.
 */
public static void loop() {

    ......
    
    //获取消息队列
    final MessageQueue queue = me.mQueue;

    ......
    
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
        // No message indicates that the message queue is quitting.
                return;
        }

        ......
        
        try { 
            //处理消息,这里的target就是Handler
            msg.target.dispatchMessage(msg);
        } finally {
            ......
        }
    }
}

通过上面的代码可以看出loop其实非常的简单,就是从消息队列中不停的取消息,然后进行消息分发。

Handler作用

Handler类用于处理消息。它有两个功能,功能一,向消息队列中发消息; 功能二,处理消息。我们来看一下它是如何实现的。

代码语言:javascript
复制
public class Handler {

    ......
    
    final Looper mLooper;       //提向Looper对象
    final MessageQueue mQueue;  //指向消息队列,它是从Looper获取的
    
    ......
    
}

Handler 向消息队列发消息的方法是 sendMessage 函数,它用于将消息插入到消息队列中。它实际调用的 MessageQueue 类的 enqueueMessage 方法。

注意,调用过程如下 sendMessage->sendMessageDelayed->sendMessageAtTime-> enqueueMessage

代码语言:javascript
复制
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    //调用的 MessageQueue的enqueueMessage方法
    return queue.enqueueMessage(msg, uptimeMillis);
}

Handler 处理消息的方法是 dispatchMessage 函数,代码如下:

代码语言:javascript
复制
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        //使用 post 方法传递消息
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
            return;
            }
        }
        //sendMessage 方法传递消息
        handleMessage(msg);
    }
}

......

private static void handleCallback(Message message) {
    //执行 消息回调的 run 方法
    message.callback.run();
}

如我们在 Looper 一节中分析过,它在分发消息时调用的是msg.target.dispatchMessage(msg); 也就是 Handler 的 dispatchMessage 方法,而Handler的dispatchMessage方法会根据消息是通过 sendMessage 插入的还是post插入的做不同的处理。

如果是sendMessage插入的,则调用 handleMessage 方法。

handleMessage函数是个重载函数,需要由用户自己进行重写。

如果是 post 插入的,则调用 handleCallback 方法,该方法又会调用 message.callback 的 run 方法。

注意,虽然调用的是 run 方法,但并未启动新的线程,所以仍然还是在当前线程中执行。

理解HandlerThread

HandlerThread应该叫LooperThread更合适,其实它就是包含了Looper对象的线程。代码如下:

代码语言:javascript
复制
public class HandlerThread extends Thread {
    ......
    Looper mLooper;
    ......   
}

也就是启动一个带Looper的线程,然后用Looper不停的读取MessageQueue中的消息,然后做分发处理。是不是非常简单?

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 常用线程模型
  • MessageQueue
  • 什么是Looper
  • Handler作用
  • 理解HandlerThread
相关产品与服务
消息队列 CMQ 版
消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档