【HarmonyOS NEXT】鸿蒙应用使用后台任务之长时任务,解决屏幕录制音乐播放等操作不被挂起

【HarmonyOS NEXT】鸿蒙应用使用后台任务之长时任务,解决屏幕录制音乐播放等操作不被挂起

一、前言

1.后台是什么?
了解后台任务和长时任务前,我们需要先明白鸿蒙的后台特性:所谓的后台,指的是设备返回主界面、锁屏、应用切换等操作会使应用退至后台这个状态。

2.鸿蒙系统为什么这么做?
当应用退至后台后,如果继续活动,可能会造成设备耗电快、用户界面卡顿等现象。鸿蒙系统为了降低设备耗电速度、保障用户使用流畅度,系统会对退至后台的应用进行管控,包括进程挂起和进程终止。

3.会有什么问题?
当系统将应用挂起后,应用进程无法使用软件资源(如公共事件、定时器等)和硬件资源(CPU、网络、GPS、蓝牙等)。

综上所述,所以才会有标题存在的问题和对应的解决方案。
当我们应用正在使用蓝牙扫描 或者 音乐播放 或者 屏幕录制等类似的操作时,只要应用退到了后台超过三秒,就会被系统挂起,强制暂停。影响我们的逻辑业务。
所以这种情况下,鸿蒙提供了后台任务来解决。

二、后台任务是什么

后台任务是鸿蒙系统提供给有在后台,做业务操作不想被挂起需求的应用,提供的一套解决方案。

根据应用业务类型不同,也分为不同的后台任务:
在这里插入图片描述
根据我们的常规使用场景,例如屏幕录制举例,就需要使用长时任务来解决应用被挂起的问题。

三、长时任务的使用:

1.首先我们需要根据自己的业务类型,选择对应的长时任务类型:
在这里插入图片描述
我们以屏幕录制举例,选择AUDIO_RECORDING

2.在module.json5配置后台任务权限和长时任务能力类型:

   "abilities": [{"backgroundModes": ["audioRecording"],}
      // 申请长时任务{"name": "ohos.permission.KEEP_BACKGROUND_RUNNING","reason": "$string:reason","usedScene": {"abilities": ["EntryAbility"],"when": "always"}},

3.在录屏开启前,调用开启长时任务,退出录屏后取消长时任务。【开启和取消的两个调用时机需要注意,相当于长时任务的生命周期,是包裹住整个后台业务的生命周期。】

开启长时任务

import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import { wantAgent, WantAgent } from '@kit.AbilityKit';/*** 开启长时任务*/startContinuousTask() {let wantAgentInfo: wantAgent.WantAgentInfo = {// 点击通知后,将要执行的动作列表// 添加需要被拉起应用的bundleName和abilityNamewants: [{bundleName: "com.test.basedemo",abilityName: "EntryAbility"}],// 指定点击通知栏消息后的动作是拉起abilityactionType: wantAgent.OperationType.START_ABILITY,// 使用者自定义的一个私有值requestCode: 0,// 点击通知后,动作执行属性actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]};try {// 通过wantAgent模块下getWantAgent方法获取WantAgent对象wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {try {backgroundTaskManager.startBackgroundRunning(getContext(),backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj, (error: BusinessError)=>{if (error) {console.error(this.TAG,`Operation startBackgroundRunning failed. code is ${error.code} message is ${error.message}`);} else {console.info(this.TAG,"Operation startBackgroundRunning succeeded");promptAction.showToast({message: "开启长时任务成功!"});// // 此处执行具体的长时任务逻辑,如录音,录制等。// this.startRecording();}})} catch (error) {console.error(this.TAG,`Operation startBackgroundRunning failed. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);}});} catch (error) {console.error(this.TAG, `Failed to Operation getWantAgent. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);}}

关闭长时任务

  /*** 暂停长时任务*/stopContinuousTask() {backgroundTaskManager.stopBackgroundRunning(getContext()).then(() => {console.info(this.TAG, `Succeeded in operationing stopBackgroundRunning.`);promptAction.showToast({message: "取消长时任务!"});}).catch((err: BusinessError) => {console.error(this.TAG, `Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);});}

源码示例:

在这里插入图片描述

module.json5

   "abilities": [{"backgroundModes": ["audioRecording"],}
      // 申请长时任务{"name": "ohos.permission.KEEP_BACKGROUND_RUNNING","reason": "$string:reason","usedScene": {"abilities": ["EntryAbility"],"when": "always"}},// 申请麦克风{"name": "ohos.permission.MICROPHONE","reason": "$string:reason","usedScene": {"abilities": ["EntryAbility"],"when": "always"}},

BackTaskTestPage.ets


import media from '@ohos.multimedia.media';
import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { wantAgent, WantAgent } from '@kit.AbilityKit';
import { fileIo as fs } from '@kit.CoreFileKit';
import { promptAction } from '@kit.ArkUI';

struct BackTaskTestPage {private TAG: string = "BackTaskTestPage";// 录屏沙箱文件private mFile: fs.File | null = null;aboutToAppear(): void {// 为了录屏可以采集麦克风,需要申请麦克风权限const atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();try {atManager.requestPermissionsFromUser(getContext(), ["ohos.permission.MICROPHONE"]).then((data) => {if (data.authResults[0] === 0) {} else {console.log(this.TAG, "user rejected")}}).catch((err: BusinessError) => {console.log(this.TAG, "BusinessError err: " + JSON.stringify(err))})} catch (err) {console.log(this.TAG, "catch err: " + JSON.stringify(err))}// 创建录制视频的沙箱文件地址let context = getContext(this) as common.UIAbilityContext; // 获取设备A的UIAbilityContext信息let pathDir: string = context.filesDir; // /data/storage/el2/base/haps/entry/fileslet filePath: string = pathDir + '/testBG.mp4';// 若文件不存在,则创建文件。let fileTarget = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);console.info(this.TAG, "file done: " + JSON.stringify(fileTarget.fd));this.mFile = fileTarget;}/*** 开启长时任务*/startContinuousTask() {let wantAgentInfo: wantAgent.WantAgentInfo = {// 点击通知后,将要执行的动作列表// 添加需要被拉起应用的bundleName和abilityNamewants: [{bundleName: "com.test.basedemo",abilityName: "EntryAbility"}],// 指定点击通知栏消息后的动作是拉起abilityactionType: wantAgent.OperationType.START_ABILITY,// 使用者自定义的一个私有值requestCode: 0,// 点击通知后,动作执行属性actionFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]};try {// 通过wantAgent模块下getWantAgent方法获取WantAgent对象wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {try {backgroundTaskManager.startBackgroundRunning(getContext(),backgroundTaskManager.BackgroundMode.AUDIO_RECORDING, wantAgentObj, (error: BusinessError)=>{if (error) {console.error(this.TAG,`Operation startBackgroundRunning failed. code is ${error.code} message is ${error.message}`);} else {console.info(this.TAG,"Operation startBackgroundRunning succeeded");promptAction.showToast({message: "开启长时任务成功!"});// // 此处执行具体的长时任务逻辑,如录音,录制等。// this.startRecording();}})} catch (error) {console.error(this.TAG,`Operation startBackgroundRunning failed. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);}});} catch (error) {console.error(this.TAG, `Failed to Operation getWantAgent. code is ${(error as BusinessError).code} message is ${(error as BusinessError).message}`);}}/*** 暂停长时任务*/stopContinuousTask() {backgroundTaskManager.stopBackgroundRunning(getContext()).then(() => {console.info(this.TAG, `Succeeded in operationing stopBackgroundRunning.`);promptAction.showToast({message: "取消长时任务!"});}).catch((err: BusinessError) => {console.error(this.TAG, `Failed to operation stopBackgroundRunning. Code is ${err.code}, message is ${err.message}`);});}build() {Row() {Column() {Button() {Text('申请长时任务').fontSize(25).fontWeight(FontWeight.Bold)}.type(ButtonType.Capsule).margin({ top: 10 }).backgroundColor('#0D9FFB').width(250).height(40).onClick(() => {// 通过按钮申请长时任务this.startContinuousTask();})Button() {Text('取消长时任务').fontSize(25).fontWeight(FontWeight.Bold)}.type(ButtonType.Capsule).margin({ top: 10 }).backgroundColor('#0D9FFB').width(250).height(40).onClick(() => {// 通过按钮取消长时任务this.stopContinuousTask();})Button() {Text('开始录制').fontSize(25).fontWeight(FontWeight.Bold)}.type(ButtonType.Capsule).margin({ top: 10 }).backgroundColor('#0D9FFB').width(250).height(40).onClick(async () => {this.startRecording();})Button() {Text('暂停录制').fontSize(25).fontWeight(FontWeight.Bold)}.type(ButtonType.Capsule).margin({ top: 10 }).backgroundColor('#0D9FFB').width(250).height(40).onClick(() => {this.stopRecording();})}.width('100%')}.height('100%')}private screenCapture?: media.AVScreenCaptureRecorder;// 调用startRecording方法可以开始一次录屏存文件的流程,结束录屏可以通过点击录屏胶囊停止按钮进行操作。public async startRecording() {this.screenCapture = await media.createAVScreenCaptureRecorder();console.info(this.TAG,"startRecording screenCapture on done" );try {let avCaptureConfig: media.AVScreenCaptureRecordConfig = {fd: this.mFile?.fd ?? 0, // 文件需要先有调用者创建,赋予写权限,将文件fd传给此参数}await this.screenCapture?.init(avCaptureConfig); // avCaptureConfig captureConfigconsole.info(this.TAG,"startRecording screenCapture init done" );} catch (err) {console.info(this.TAG,"startRecording init err: " + JSON.stringify(err) );}await this.screenCapture?.startRecording();console.info(this.TAG,"startRecording screenCapture startRecording" );}// 可以主动调用stopRecording方法来停止录屏。public async stopRecording() {if (this.screenCapture == undefined) {// Errorreturn;}await this.screenCapture?.stopRecording();// 调用release()方法销毁实例,释放资源。await this.screenCapture?.release();// 最后需要关闭创建的录屏文件fd, fs.close(fd);fs.closeSync(this.mFile);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/66575.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nvm实现nodejs的版本管理

部分老旧项目需要使用低版本的node,网上很多是无效的,高版本无法直接安装低版本node,但是低版本nodejs可以安装部分高版本node,从而达到升级效果。 NVM安装 nvm是什么 nvm全英文也叫node.js version management,是一个…

基于华为ENSP的OSPF接口网络类型深入浅出(4)

本篇技术博文摘要 🌟 OSPF的接口在不同网络类型下的工作方式;不同网络类型下的报文通告方式深入浅出hub-spoke架构 引言 📘 在这个快速发展的技术时代,与时俱进是每个IT人的必修课。我是肾透侧视攻城狮,一名什么都会一…

【深度学习】多目标融合算法(二):底部共享多任务模型(Shared-Bottom Multi-task Model)

目录 一、引言 1.1 往期回顾 1.2 本期概要 二、Shared-Bottom Multi-task Model(SBMM) 2.1 技术原理 2.2 技术优缺点 2.3 业务代码实践 三、总结 一、引言 在朴素的深度学习ctr预估模型中(如DNN),通常以一个行…

TVbox 手机、智能电视节目一网打尽

文章目录 一、简要介绍二、优点三、下载地址 一、简要介绍 TVbox是目前最火爆的多端、多源的电视影音工具,是一款开源的自定义添加站源的影音工具。TVBox,支持电视频道直播。一款TV端影视工具,软件本身不具有任何影视资源,但可以…

2025新春烟花代码(二)HTML5实现孔明灯和烟花效果

效果展示 源代码 <!DOCTYPE html> <html lang"en"> <script>var _hmt _hmt || [];(function () {var hm document.createElement("script");hm.src "https://hm.baidu.com/hm.js?45f95f1bfde85c7777c3d1157e8c2d34";var …

ue5 蒙太奇,即上半身动画和下半身组合在一起,并使用。学习b站库得科技

本文核心 正常跑步动画端枪动画跑起来也端枪 正常跑步动画 端枪动画的上半身 跑起来也端枪 三步走&#xff1a; 第一步制作动画蒙太奇和插槽 第二步动画蓝图选择使用上半身动画还是全身动画&#xff0c;将上半身端枪和下半身走路结合 第三步使用动画蒙太奇 1.开始把&a…

YOLOv8实战人员跌倒检测

本文采用YOLOv8作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv8以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对人员跌倒目标数据集进行训练和优化&#xff0c;该数据集包含丰富人员跌倒图像样…

C#进阶-在Ubuntu上部署ASP.NET Core Web API应用

随着云计算和容器化技术的普及&#xff0c;Linux 服务器已成为部署 Web 应用程序的主流平台之一。ASP.NET Core 作为一个跨平台、高性能的框架&#xff0c;非常适合在 Linux 环境中运行。本篇博客将详细介绍如何在 Linux 服务器上部署 ASP.NET Core Web API 应用&#xff0c;包…

【网页自动化】篡改猴入门教程

安装篡改猴 打开浏览器扩展商店&#xff08;Edge、Chrome、Firefox 等&#xff09;。搜索 Tampermonkey 并安装。 如图安装后&#xff0c;浏览器右上角会显示一个带有猴子图标的按钮。 创建用户脚本 已进入篡改猴管理面板点击创建 脚本注释说明 name&#xff1a;脚本名称。…

数据结构之双链表(C语言)

​ 数据结构之双链表&#xff08;C语言&#xff09; 1 链表的分类2 双向链表的结构3 双向链表的节点创建与初始化3.1 节点创建函数3.2 初始化函数 4 双向链表插入节点与删除节点的前序分析5 双向链表尾插法与头插法5.1 尾插函数5.2 头插函数 6 双向链表的尾删法与头删法6.1尾删…

【0x007A】HCI_Write_Secure_Connections_Host_Support命令详解

目录 一、命令概述 二、命令格式及参数 2.1. HCI_Write_Secure_Connections_Host_Support命令格式 2.2. Secure_Connections_Host_Support 三、生成事件及参数 3.1. HCI_Command_Complete事件格式 3.2. Status 四、命令执行流程梳理 4.1. 命令发送阶段 4.2. 命令接收…

第一节 环境搭建

Visual Studio Visual Studio 2019 密码&#xff1a;gd24 组件 安装即可

《Spring Framework实战》4:Spring Framework 文档

欢迎观看《Spring Framework实战》视频教程 概述 历史&#xff0c; 设计理念&#xff0c; 反馈&#xff0c; 开始。 核心技术 IoC 容器、事件、资源、i18n、 验证、数据绑定、类型转换、SpEL、AOP、AOT。 测试 Mock 对象、TestContext 框架、 Spring MVC 测试&#xff0c;…

【adb】5分钟入门adb操作安卓设备

ADB&#xff08;Android Debug Bridge&#xff09; 是一个多功能的命令行工具&#xff0c;用于与 Android 设备进行交互、调试和管理。它提供了对设备的直接控制&#xff0c;能够帮助开发者进行调试、安装应用、传输文件等。 目录 将设备和电脑连接 adb shell 文件的基本操…

Tauri教程-基础篇-第二节 Tauri的核心概念上篇

“如果结果不如你所愿&#xff0c;就在尘埃落定前奋力一搏。”——《夏目友人帐》 “有些事不是看到了希望才去坚持&#xff0c;而是因为坚持才会看到希望。”——《十宗罪》 “维持现状意味着空耗你的努力和生命。”——纪伯伦 Tauri 技术教程 * 第四章 Tauri的基础教程 第二节…

Ubuntu 下载安装 elasticsearch7.17.9

参考 https://blog.csdn.net/qq_26039331/article/details/115024218 https://blog.csdn.net/mengo1234/article/details/104989382 过程 来到 Es 的版本发布列表页面&#xff1a;https://www.elastic.co/downloads/past-releases#elasticsearch 根据自己的系统以及要安装的…

深度学习与计算机视觉 (博士)

文章目录 零、计算机视觉概述一、深度学习相关概念1.学习率η2.batchsize和epoch3.端到端(End-to-End)、序列到序列(Seq-to-Seq)4.消融实验5.学习方式6.监督学习的方式(1)有监督学习(2)强监督学习(3)弱监督学习(4)半监督学习(5)自监督学习(6)无监督学习(7)总结&#xff1a;不同…

深入Android架构(从线程到AIDL)_18 SurfaceView的UI多线程02

目录 2、 使用SurfaceView画2D图 范例一 设计GameLoop(把小线程移出来) 范例二 2、 使用SurfaceView画2D图 范例一 以SurfaceView绘出Bitmap图像设计SpriteView类别来实作SurfaceHolder.Callback接口首先来看个简单的程序&#xff0c;显示出一个Bitmap图像。这个图像就构…

数据库相关面试重点知识

一、Mysql索引 1.索引的本质 索引是帮助 Mysql 高效获取数据的排好序的数据结构。 索引的数据结构&#xff1a; 二叉树红黑树Hash表B-Tree&#xff08;BTree&#xff09; Question&#xff1a;为什么加入索引之后效率就会变高呢&#xff1f; 以上图为例&#xff0c;如果…

ansible-api分析(VariableManager变量)

一. 简述&#xff1a; ansible是一个非常强大的工具&#xff0c;可以支持多种类型(字符,数字,列表&#xff0c;字典等)的变量。除了有大量的内置变量及fact变量&#xff0c;也可以通过多种方式进行变量自定义 。不同方式定义的变量&#xff0c;优先级也不太一样&#xff0c;之…