鸿蒙|性能优化-后台任务低功耗

1 阅读6分钟

概览:本文介绍了后台应用的功耗管理,涵盖后台任务、硬件资源和软件资源的使用规范。包括后台任务的特性、不同类型任务的应用场景,以及后台硬件和软件资源(如蓝牙、网络、音频等)的合理使用和功耗优化建议。

什么是后台任务功耗?

后台任务:是指那些不需要与用户直接交互,或者仅在用户不可见的情况下运行的任务,具有非交互性、低优先级、资源占用较少等特点。

后台任务功耗:指应用在用户不可见且未与其交互时的功耗,与前台任务相比,后台任务通常不需要处理大量的UI更新和事件,因此功耗相对较低。然而,后台任务仍然需要执行一些必要的操作,如数据同步、状态更新等,这些操作也会消耗一定的资源。

应用后台运行的设计与实现

任务类型概念应用退至后台状态适用场景
无后台不执行任务,直接退到后台。应用在几秒内挂起。适用于大多数场景。即用户无持续使用需求、任务,具有明确终点、无需后台数据处理的应用,如计算器、手电筒、相册等。
短时任务实时性高、耗时不长的任务。在单次配额内,应用不会被挂起,直到取消任务。配额超时不取消,应用进程会被终止。小文件下载、缓存、信息发送等任务需要临时占用资源执行。
长时任务长时间运行、用户可感知的任务。应用不会被挂起,直到取消任务。任务结束不取消,应用进程会被终止。数据传输、音频播放、录音、定位导航、蓝牙、WLAN 相关、多设备互联、音视频通话、计算任务。
延迟任务实时性不高、可延迟执行的任务,满足条件后放入执行队列,系统统一调度。应用退到后台时挂起,满足条件后系统统一调度拉起应用,创建Extension进程执行任务。单次回调最长运行2分钟,超时不取消,系统终止Extension进程。软件更新、信息收集、数据处理等。
代理提醒系统代理应用提醒。应用挂起或进程终止,满足条件后系统代理应用提醒。闹钟、倒计时、日历。

截屏2026-03-25 11.16.50.png

案例:后台申请短时任务

短时任务概念:在应用进行小文件下载、缓存、信息发送等业务场景时,如果应用短暂退至后台导致 进程被挂起,重新切换到前台可能会出现异常状态。此时,可以申请短时任务作为解决方案。以下示例展 示了如何使用ApplicationContext订阅应用前后台切换的回调,以在应用切后台时申请短时任务,解决因 短暂切换前后台导致的消息发送异常问题。

1、系统息屏场景/应用置于后台场景:前台应用在自动息屏后,会被识别为置于后台。此时,应用可以申请短时任务,默认剩余时长上限为三分钟。

2、当短时任务的剩余时间不足时,系统会触发回调,停止任务。

module.json5

"requestPermissions": [
  {
    // 保持应用在后台持续运行(用于长/短时任务退后台,允许Service Ability在后台持续运行)
    "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
    "reason": "$string:permission_keep_background_running_desc",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "inuse"
    }
  }
],

resources > base > element > string.json

{
  "name": "permission_keep_background_running_desc",
  "value": "It is used to backtrack long/short tasks, allowing Service Ability to run continuously in the background"
},

ets > pages > Index.ets

import { hilog } from '@kit.PerformanceAnalysisKit';
import suspendTaskUtils from '../utils/SuspendTaskUtils';
import { ShortTermTaskModel } from '../viewModel/ShortTermTaskModel';


@Entry
@Component
struct Index {
  private shortTermTaskModel: ShortTermTaskModel = new ShortTermTaskModel();
  private messageCount: number = 0;
  private taskTimer = 0;

  aboutToDisappear(): void {
    clearInterval(this.taskTimer);
    suspendTaskUtils.cancelSuspendDelay(this.shortTermTaskModel.suspendTaskInfo.id);
    this.shortTermTaskModel.offAppStateChange();
  }

  build() {
    Column({ space: 20 }) {
      Button('开启应用程序状态监听,切换到后台时申请短时任务')
        .width('95%')
        .onClick(() => {
          this.shortTermTaskModel.subscribeStateChange();
          this.taskTimer = setInterval(() => {
            this.messageCount++;
            hilog.info(0x0000, 'short_term_task', `already sent :${this.messageCount} messages`);
          }, 2000);
        })
      Button('获取应用程序进入挂起状态前的剩余时间')
        .width('95%')
        .onClick(async () => {
          try {
            let delayTime = await suspendTaskUtils.getRemainingDelayTime(this.shortTermTaskModel.suspendTaskInfo.id);
            this.getUIContext().getPromptAction().showToast({
              message: '应用程序进入挂起状态前的剩余时间:' + delayTime
            });
          } catch (err) {
            this.getUIContext().getPromptAction().showToast({
              message: '获取剩余时间失败,请先将应用置于后台,随后再次返回此页面,重新点击该按钮'
            });
          }
        })
      Button('取消短时任务')
        .width('95%')
        .onClick(() => {
          suspendTaskUtils.cancelSuspendDelay(this.shortTermTaskModel.suspendTaskInfo.id);
        })
      Button('关闭应用程序状态监听')
        .width('95%')
        .onClick(() => {
          clearInterval(this.taskTimer);
          this.shortTermTaskModel.offAppStateChange();
        })
    }
    .height('100%')
    .width('100%')
  }
}

entryability > EntryAbility.ets > onCreate

AppStorage.setOrCreate('context', this.context);

ets > viewModel > ShortTermTaskModel.ets

import { ApplicationStateChangeCallback, common } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import suspendTaskUtils from '../utils/SuspendTaskUtils';
import { SuspendTaskInfo } from './SuspendTaskInfo';


const TAG: string = 'short_term_task';

export class ShortTermTaskModel {
  public suspendTaskInfo: SuspendTaskInfo = { id: 0, delayTime: 0 };
  private context: common.UIAbilityContext = AppStorage.get("context") as common.UIAbilityContext;

  // 开启应用程序状态监听
  subscribeStateChange() {
    let that = this;
    let applicationContext = this.context.getApplicationContext();
    let applicationStateChangeCallback: ApplicationStateChangeCallback = {
      onApplicationForeground() {
        hilog.info(0x0000, TAG, 'applicationStateChangeCallback onApplicationForeground');
      },
      onApplicationBackground() {
        hilog.info(0x0000, TAG, 'applicationStateChangeCallback onApplicationBackground');
        // 当应用从前台切换到后台时申请短时任务
        that.suspendTaskInfo = suspendTaskUtils.requestSuspendDelay('Suspend Task');
        hilog.info(0x0000, TAG,
          `requestSuspendDelay, id:${that.suspendTaskInfo.id}, delayTime:${that.suspendTaskInfo.delayTime}`);
      }
    }
    try {
      applicationContext.on('applicationStateChange', applicationStateChangeCallback);
    } catch (paramError) {
      hilog.error(0x0000, TAG,
        `error: ${(paramError as BusinessError).code}, ${(paramError as BusinessError).message}`);
    }
  }


  // 关闭应用程序状态监听
  offAppStateChange(): void {
    let applicationContext = this.context.getApplicationContext();
    try {
      applicationContext.off('applicationStateChange');
      hilog.info(0x0000, TAG, 'ApplicationStateChange off succeeded.');
    } catch (paramError) {
      hilog.error(0x0000, TAG,
        `error: ${(paramError as BusinessError).code}, ${(paramError as BusinessError).message}`);
    }
  }
}

ets > utils > SuspendTaskUtils.ets

import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { SuspendTaskInfo } from '../viewModel/SuspendTaskInfo';

const TAG: string = 'short_term_task';

/**
 * 挂起任务工具类
 */
class SuspendTaskUtils {
  /**
   * 申请短时任务
   * @param reason 设置延迟任务暂停原因
   * @returns
   */
  requestSuspendDelay(reason: string): SuspendTaskInfo {
    let id: number; // 短时任务 ID
    let delayTime: number; // 应用程序进入挂起状态前的剩余时间
    try {
      // 请求短时任务
      let delayInfo = backgroundTaskManager.requestSuspendDelay(reason,() => {
        // 此函数用于在应用程序请求的短时任务即将超时时回调应用程序
        hilog.info(0x0000, TAG, `Request suspension delay will time out.`);
        backgroundTaskManager.cancelSuspendDelay(delayInfo.requestId);
      })
      id = delayInfo.requestId;
      delayTime = delayInfo.actualDelayTime;

      let taskInfo = {
        id: id,
        delayTime: delayTime
      } as SuspendTaskInfo;
      return taskInfo;
    } catch (err) {
      let taskInfo = {
        id: 0,
        delayTime: 0
      } as SuspendTaskInfo;
      return taskInfo;
    }
  }

  /**
   * 获取短时任务的剩余时间
   * @param id 短时任务ID
   * @returns
   */
  async getRemainingDelayTime(id: number): Promise<number> {
    let delayTime: number = -1;
    await backgroundTaskManager.getRemainingDelayTime(id).then((res: number) => {
      delayTime = res;
      hilog.info(0x0000, TAG, 'Operation getRemainingDelayTime succeeded. Data: ' + JSON.stringify(res));
    }).catch((err: BusinessError) => {
      hilog.error(0x0000, TAG, 'Operation getRemainingDelayTime failed. Cause: ' + err.code);
    });
    return delayTime;
  }

  /**
   * 取消短时任务
   * @param id 短时任务ID
   * @returns
   */
  cancelSuspendDelay(id: number): boolean {
    try {
      backgroundTaskManager.cancelSuspendDelay(id);
      hilog.info(0x0000, TAG, 'cancelSuspendDelay succeeded.');
    } catch (err) {
      hilog.error(0x0000, TAG, `cancelSuspendDelay failed. Cause: ${JSON.stringify(err)}`);
      return false;
    }
    return true;
  }
}

let suspendTaskUtils = new SuspendTaskUtils();

export default suspendTaskUtils as SuspendTaskUtils;

ets > viewModel > SuspendTaskInfo.ets

export interface SuspendTaskInfo {
  id: number; // 短时任务 ID
  delayTime: number; // 应用程序进入挂起状态前的剩余时间
}

案例:后台申请长时任务

长时任务概念:当应用涉及数据传输、音频播放、录音操作、定位导航、蓝牙和WLAN相关应用、多 设备互联、音视频通话、复杂计算任务等场景时,需要应用在后台长时间运行。为了确保应用在这些情况下 正常运作,可以申请后台长时任务来实现。以下示例展示了如何使用长时任务管理应用的定位服务,以实现 应用在后台长时间运行时,持续获取设备位置信息的功能。

1.使用定位应用场景,应用前台运行时开启位置订阅,控制台定期打印位置信息,说明长时任务执行。

2.应用退至后台持续运行,控制台日志还会定时打印位置信息,说明任务仍被执行。

module.json5

"abilities": [
  {
    "name": "EntryAbility",
    // 用于定义应用在后台运行时可以执行的任务类型,location表示允许应用在后台获取位置信息
    "backgroundModes": [
      'location'
    ]
  }
],

"requestPermissions": [
  {
    // 获取精准定位(用于长时任务页面,允许应用获取设备位置信息)
    "name": "ohos.permission.LOCATION",
    "reason": "$string:permission_location_desc",
    "usedScene": {
      "abilities": [
        "EntryAbility"
      ],
      "when": "inuse"
    },
  },
  {
    // 用于后台定位的场景(用于长时任务页面,允许应用在后台运行时获取设备位置信息)
    "name": "ohos.permission.LOCATION_IN_BACKGROUND",
    "reason": "$string:permission_location_background_desc",
    "usedScene": {
      "abilities": [
        "EntryAbility"
      ],
      "when": "inuse"
    },
  },
  {
    // 获取模糊定位(用于长时任务页面,允许应用获取设备模糊位置信息)
    "name": "ohos.permission.APPROXIMATELY_LOCATION",
    "reason": "$string:permission_approximately_location_desc",
    "usedScene": {
      "abilities": [
        "EntryAbility"
      ],
      "when": "inuse"
    },
  },
  {
    // 保持应用在后台持续运行(用于长/短时任务退后台,允许Service Ability在后台持续运行)
    "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
    "reason": "$string:permission_keep_background_running_desc",
    "usedScene": {
      "abilities": [
        "EntryAbility"
      ],
      "when": "inuse"
    },
  }
]

resources > base > element > string.json

{
  "name": "permission_location_desc",
  "value": "Used for long task pages to allow applications to obtain device location information"
},
{
  "name": "permission_location_background_desc",
  "value": "Used for long task pages to allow applications to obtain device location information while running in the background"
},
{
  "name": "permission_approximately_location_desc",
  "value": "Used for long task pages to allow applications to get fuzzy device location information"
},
{
  "name": "permission_keep_background_running_desc",
  "value": "It is used to backtrack long/short tasks, allowing Service Ability to run continuously in the background"
}

ets > pages > Index.ets

private longTermTaskModel: LongTermTaskModel = new LongTermTaskModel();

aboutToDisappear(): void {
  geoLocationManager.off('locationChange');
  this.longTermTaskModel.stopLongTask();
}

Button('申请定位权限')
  .onClick(() => {
    this.longTermTaskModel.requestPermissionsFromUser();
  })
Button('开启定位服务')
  .onClick(() => {
    this.longTermTaskModel.startLongTask();
    this.longTermTaskModel.getLocation();
  })
Button('关闭定位服务')
  .onClick(async () => {
    geoLocationManager.off('locationChange');
    this.longTermTaskModel.stopLongTask();
  })

ets > viewModel > LongTermTaskModel.ets

import { abilityAccessCtrl, common, PermissionRequestResult, Permissions, wantAgent, WantAgent } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { backgroundTaskManager } from '@kit.BackgroundTasksKit';
import { geoLocationManager } from '@kit.LocationKit';

const TAG: string = 'long_term_task';

export class LongTermTaskModel {
  private context: common.UIAbilityContext = AppStorage.get("context") as common.UIAbilityContext;

  // 申请与位置相关的权限
  requestPermissionsFromUser(): void {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    let permissionList: Permissions[] = [
      'ohos.permission.INTERNET',               // 允许应用访问网络权限
      'ohos.permission.LOCATION',               // 精准定位权限
      'ohos.permission.APPROXIMATELY_LOCATION'  // 模糊定位权限
    ];
    atManager.requestPermissionsFromUser(this.context, permissionList)
      .then((data: PermissionRequestResult) => {
        hilog.info(0x0000, TAG, `data: ${JSON.stringify(data)}`);
      })
      .catch((err: BusinessError) => {
        hilog.error(0x0000, TAG, `requestPermissionsFromUser fail: ${JSON.stringify(err)}`);
      });
  }

  // 位置信息回调
  locationCallback = async (location: geoLocationManager.Location) => {
    hilog.info(0x0000, TAG, `locationCallback: data: ${JSON.stringify(location)}`);
  };

  // 获取位置
  async getLocation() {
    let request: geoLocationManager.LocationRequest = {
      priority: geoLocationManager.LocationRequestPriority.FIRST_FIX, // 快速获取位置优先
      scenario: geoLocationManager.LocationRequestScenario.UNSET, // 表示场景信息。当scenario取值为UNSET时,priority参数生效
      timeInterval: 1, // 上报位置信息的时间间隔
      distanceInterval: 0, // 上报位置信息的距离间隔
      maxAccuracy: 100 // 应用向系统请求位置信息时要求的精度值
    };
    try {
      // 开启订阅请求,当位置发生改变时再次发起定位请求
      geoLocationManager.on('locationChange', request, this.locationCallback);
    } catch (err) {
      hilog.error(0x0000, TAG, `errCode: ${JSON.stringify(err)}`);
    }
  }

  // 开启长时任务
  startLongTask(): void {
    let wantAgentInfo: wantAgent.WantAgentInfo = {
      wants: [
        {
          bundleName: this.context.abilityInfo.bundleName,
          abilityName: this.context.abilityInfo.name
        }
      ],
      actionType: wantAgent.OperationType.START_ABILITY,
      requestCode: 0,
      wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
    };

    try {
      // wantAgent对象通过WantAgent模块中的getWantAgent方法获取
      wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj: WantAgent) => {
        // 应用退至后台需持续运行时,通过该接口申请长时任务
        backgroundTaskManager.startBackgroundRunning(this.context,
          backgroundTaskManager.BackgroundMode.LOCATION,wantAgentObj).then(() => {
            hilog.info(0x0000, TAG, `Operation startBackgroundRunning succeeded`);
        })
          .catch((error:BusinessError) => {
            hilog.error(0x0000, TAG, `Operation startBackgroundRunning failed. code is ${error.code} message is ${error.message}`);
          })
      });
    } catch (error) {
      hilog.error(0x0000, TAG, `Operation getWantAgent failed. error is ${JSON.stringify(error)} `);
    }
  }

  // 停止长时任务
  stopLongTask(): void {
    // 停止长时任务
    backgroundTaskManager.stopBackgroundRunning(this.context).then(() => {
      hilog.info(0x0000, TAG, `Operation stopBackgroundRunning succeeded`);
    }).catch((error: BusinessError) => {
      hilog.error(0x0000, TAG, `Operation stopBackgroundRunning failed. error is ${JSON.stringify(error)} `);
    });
  }
}

后台硬件资源合理使用汇总

控制后台进程CPU使用率:developer.huawei.com/consumer/cn…

蓝牙资源合理使用:developer.huawei.com/consumer/cn…

网络资源合理使用:developer.huawei.com/consumer/cn…

音频资源合理使用:developer.huawei.com/consumer/cn…

GPS资源合理使用:developer.huawei.com/consumer/cn…

传感器资源合理使用:developer.huawei.com/consumer/cn…

后台软件资源合理使用汇总

后台上传下载合理使用:developer.huawei.com/consumer/cn…

后台音频播放合理使用:developer.huawei.com/consumer/cn…

后台定位导航服务合理使用:developer.huawei.com/consumer/cn…

后台系统资源合理使用:developer.huawei.com/consumer/cn…

后台场景应用功耗体验建议汇总

后台任务使用:developer.huawei.com/consumer/cn…

后台硬件资源使用:developer.huawei.com/consumer/cn…

后台软件资源使用:developer.huawei.com/consumer/cn…