# 应用后台运行

## 概述

为有效降低设备耗电量并确保用户体验流畅，系统会对后台应用进行管理，包括进程挂起和终止。当应用处于音乐播放或地图导航等场景时，如果用户将应用退至后台、锁屏或切换应用，系统会自动将应用转入后台运行。为确保应用在后台期间仍能正常使用，系统提供了符合规范的后台任务机制。本文将介绍应用切后台的常见问题及解决方案，并通过分析应用短暂切换前后台和后台长时间运行的开发实践案例，指导开发者如何有效使用后台任务处理冻结场景，从而确保应用在前后台之间能够流畅切换。

**应用后台规格建议**

当前系统将对切换至后台的应用程序所使用的资源进行严格管控，具体措施包括挂起和终止进程。如果不进行后台处理，可能会导致应用程序功能异常。请参考官网指南和最佳实践文档，了解具体的限制条件和建议。

* [后台硬件资源使用](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/standard-background-hardware)、[后台硬件资源合理使用](https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-use-of-background-hardware-resources)：后台进程CPU负载约束（长时任务、短时任务）；应用退到后台无长时任务时使用蓝牙、网络资源、麦克风或者扬声器、GPS资源；退到后台禁止使用传感器。
* [后台软件资源使用](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/standard-background-software)、[后台软件资源合理使用](https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-use-of-background-software-resources)：后台合理使用上传下载、使用音频服务、使用定位导航服务、使用系统资源。
* [Background Tasks Kit简介](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/background-task-overview)：后台任务的功能介绍、资源使用约束、后台任务类型。

## 实现原理

### 后台任务类型

标准系统支持规范内受约束的后台任务，包括短时任务、长时任务、延迟任务、代理提醒。开发者可以根据如下介绍，选择合适的[后台任务类型](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/background-task-overview#后台任务类型)，以满足应用退至后台后继续运行的需求。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/89/v3/WQL3v7lPTcKtSCEbbu5ctQ/zh-cn_image_0000002193850856.png?HW-CC-KV=V1&HW-CC-Date=20261102T125903Z&HW-CC-Expire=31536000000&HW-CC-Sign=95045137D3E51D8486A43917A98EC64F19A0B57E4510CCF276C1AC03C7525BF4 "点击放大")

以下表格对比总结了各类后台任务的概念、适用场景以及任务执行过程中的应用状态。

|适用场景|概念|常见问题|应用退至后台状态|任务类型|
|:-------------------------------------------------|:------------------------------------------------------|:---------------|:--------------------------------------------------------------------------------------------|:---|
|不执行任何任务的后台场景：直接退至后台。|不执行任何任务，直接退至后台。|-|几秒后应用挂起。|无后台|
|任务类型：小文件下载、缓存、信息发送等时效性高、需要临时占用资源的任务。|任务类型：实时性要求高、耗时不长的任务。|应用短暂切换前后台，进程被挂起。|在单次配额内，应用不会被挂起直到取消任务。单次配额超时不取消，应用进程会被终止。|短时任务|
|任务类型：数据传输、音频播放、录音、定位导航、蓝牙、WLAN相关、多设备互联、音视频通话、计算任务。|任务类型：长时间运行在后台且用户可感知的任务。|应用后台长时间运行后会中断。|应用不会被挂起，直到任务取消。如果任务结束时不取消应用进程，进程会被终止。|长时任务|
|任务类型：软件更新、信息收集、数据处理等。|任务类型：实时性要求不高、可延迟执行的任务。满足条件后，任务将放入执行队列，系统会根据内存和功耗进行统一调度。|-|应用退到后台时会挂起，满足任务设定条件时由系统统一调度拉起应用，创建Extension进程执行任务。单次回调最长运行时间为2分钟，如果超时未取消，系统会终止对应的Extension进程。|延迟任务|
|任务类型：闹钟、倒计时、日历。|任务类型：系统代理应用做出相应提醒。|-|应用挂起或进程终止时，满足条件后系统会自动进行相应的提醒。|代理提醒|

## 场景示例

### 应用短暂切换前后台，避免进程挂起

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

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/11/v3/YBP3f3JtTD2gHE0ISlZcPA/zh-cn_image_0000002193850852.png?HW-CC-KV=V1&HW-CC-Date=20261102T125903Z&HW-CC-Expire=31536000000&HW-CC-Sign=1DF9E360E92C82C6CDC66C746364238D67B33EC18C8E43B0CCFA6B9D9E3A8A9C "点击放大")

1. 定义短时任务信息SuspendTaskInfo()接口，包括短时任务的ID和获取对应短时任务的剩余时间delayTime。

   ```typescript
   export interface SuspendTaskInfo {
     id: number; // Short-time task ID
     delayTime: number; // The remaining time of this request short assignment
   }
   ```

2. 在信息发送的场景中，当应用处于前台时，在onAppear()回调函数中启动一个定时器，每隔2秒发送一条消息，模拟后台业务。

   ```typescript
   NavDestination() {
     // ...
   }
   .title(this.builderTitle())
   .onAppear(() => {
     this.shortTermTaskModel.subscribeStateChange();
     this.taskTimer = setInterval(() => {
       this.messageCount++;
       hilog.info(0x0000, TAG, `already sent ：${this.messageCount} messages`);
     }, 2000);
   })
   ```

3. 在信息发送的场景中，通过ApplicationContext.on('applicationStateChange')注册对当前应用前后台变化的监听。当应用退至后台时，触发onApplicationBackground()回调函数，在此回调函数中申请短时任务。

   ```typescript
   // Apply front - and back-end status monitoring
   subscribeStateChange() {
     let that = this;
     // Gets applicationContext
     let applicationContext = this.context.getApplicationContext();
     let applicationStateChangeCallback: ApplicationStateChangeCallback = {
       onApplicationForeground() {
         hilog.info(0x0000, TAG, 'applicationStateChangeCallback onApplicationForeground');
       },
       onApplicationBackground() {
         hilog.info(0x0000, TAG, 'applicationStateChangeCallback onApplicationBackground');
         // Apply for short-time tasks when the application changes from foreground to background
         that.suspendTaskInfo = SuspendTaskUtils.requestSuspendDelay('Suspend Task');
         hilog.info(0x0000, TAG,
           `requestSuspendDelay, id:${that.suspendTaskInfo.id}, delayTime:${that.suspendTaskInfo.delayTime}`);
       }
     }
     try {
       // Registers the background and pre - application status monitoring through applicationContext
       applicationContext.on('applicationStateChange', applicationStateChangeCallback);
     } catch (paramError) {
       hilog.error(0x0000, TAG,
         `error: ${(paramError as BusinessError).code}, ${(paramError as BusinessError).message}`);
     }
   }
   ```

4. 在小文件下载、缓存、信息发送等场景中，应用退至后台时，可使用backgroundTaskManager.requestSuspendDelay()接口，后台应用申请短时任务。短时任务的申请和使用过程中的约束与限制请参考短时任务（ArkTS）的[约束与限制](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/transient-task#约束与限制)。

   ```typescript
   /**
    *
    * @param reason Set the delay task suspension reason
    * @returns
    */
   requestSuspendDelay(reason: string): SuspendTaskInfo {
     let id: number; // Apply for a short-time task ID
     let delayTime: number; // The remaining time of this request short assignment
     try {
       // Request deferred task
       let delayInfo = backgroundTaskManager.requestSuspendDelay(reason, () => {
         // This function is used to call back the application when a short task requested by the application is about to time out.
         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;
     }
   }
   ```

5. 应用返回前台后，调用backgroundTaskManager.getRemainingDelayTime()接口，获取对应短时任务的剩余时间。

   ```typescript
   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;
   }
   ```

6. 应用退至后台，可调用backgroundTaskManager.cancelSuspendDelay()接口取消短时任务。

   ```typescript
   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;
   }
   ```

**实现效果**

* **系统息屏场景/应用置于后台场景：** 前台应用在自动息屏后，会被识别为置于后台。此时，应用可以申请短时任务，剩余时长上限为3分钟（如下图所示，delayTime为180000ms）。![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/de/v3/txZ5ey7VSYO3cv4KCgl2cQ/zh-cn_image_0000002193850864.png?HW-CC-KV=V1&HW-CC-Date=20261102T125903Z&HW-CC-Expire=31536000000&HW-CC-Sign=FBDDC4F230324F950E955D6E98FCED64593EDBFE4885D5C7EB07B52EA2EF0788)
* 当短时任务的剩余时间不足时，系统会触发回调，停止任务。![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/e8/v3/AnYAdFM9QE6QoGNyW3meRQ/zh-cn_image_0000002229450725.png?HW-CC-KV=V1&HW-CC-Date=20261102T125903Z&HW-CC-Expire=31536000000&HW-CC-Sign=C10D6CA28E0B76C04E53A6897268583E191DED81DBC3DA73FC5D2C1213BF64AF)

### 应用后台长时间运行不中断

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

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/d5/v3/1OTN2cVCSTa0wCIRLPhF9Q/zh-cn_image_0000002194010444.png?HW-CC-KV=V1&HW-CC-Date=20261102T125903Z&HW-CC-Expire=31536000000&HW-CC-Sign=F07008B5C20CFD37BCD45B76B33B6E3A41B1ED27502D0BE08E98B3E9FE611392 "点击放大")

1. 在定位、导航类的应用场景下，为了确保应用在后台仍能使用定位服务，需在module.json5配置文件中为EntryAbility声明定位类型的长时任务，并申请定位相关权限。

   ```json
   {
     "module": {
       // ...
       "abilities": [
         {
           "name": "EntryAbility",
           "srcEntry": "./ets/entryability/EntryAbility.ets",
           // ...
           "backgroundModes": [
             'location'
           ]
         }
       ],
       // ...
       "requestPermissions": [
         {
           "name": "ohos.permission.LOCATION",
           // ...
         },
         {
           "name": "ohos.permission.LOCATION_IN_BACKGROUND",
           // ...
         },
         {
           "name": "ohos.permission.APPROXIMATELY_LOCATION",
           // ...
         },
         {
           "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
           // ...
         }
       ]
     }
   }
   ```

2. 应用跳转到定位功能页面，系统请求定位权限和网络访问权限。

   ```typescript
   // Apply for location-related permissions
   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)}`);
       });
   }
   ```

3. 应用需获取位置信息，使用geoLocationManager.on('locationChange')接口，开启位置变化订阅并发起定位请求。

   ```typescript
   locationCallback = async (location: geoLocationManager.Location) => {
     hilog.info(0x0000, TAG, `locationCallback: data: ${JSON.stringify(location)}`);
   };

   // Get the location
   async getLocation() {
     let request: geoLocationManager.LocationRequest = {
       priority: geoLocationManager.LocationRequestPriority.FIRST_FIX, // Quick location acquisition is preferred
       scenario: geoLocationManager.LocationRequestScenario.UNSET, // Indicates that no scenario information is set
       timeInterval: 1, // Interval for reporting the location information
       distanceInterval: 0, // Distance for reporting location information
       maxAccuracy: 100 // The precision value required when the application requests location information from the system
     };
     try {
       geoLocationManager.on('locationChange', request, this.locationCallback);
     } catch (err) {
       hilog.error(0x0000, TAG, `errCode: ${JSON.stringify(err)}`);
     }
   }
   ```

4. 应用退至后台需持续运行时，应调用backgroundTaskManager.startBackgroundRunning()接口申请长时任务。

   ```typescript
   // Start a long task
   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 object is obtained by getWantAgent method in WantAgent module
       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)} `);
     }
   }
   ```

5. 在定位和导航类的应用场景中，当应用退出时，需调用geoLocationManager.off('locationChange')接口，关闭位置变化订阅。

   ```typescript
   geoLocationManager.off('locationChange');
   ```

6. 应用退出时，调用backgroundTaskManager.stopBackgroundRunning()接口，取消长时任务。

   ```typescript
   // Stop a long task
   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)} `);
     });
   }
   ```

**实现效果**

* 在定位和导航应用场景中，应用前台运行时开启位置订阅，控制台定期打印位置信息。![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/68/v3/DVhUBvnXQx6Ai_lzToK7iw/zh-cn_image_0000002229450733.png?HW-CC-KV=V1&HW-CC-Date=20261102T125903Z&HW-CC-Expire=31536000000&HW-CC-Sign=755BCE25D83B8C9E5977B9CCA553713C1C2538927DCCE483D506447564E1F8F7)


* 在定位和导航应用场景中，应用退至后台持续运行，控制台日志定时打印位置信息。![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/86/v3/EJtlkH_aTWWqMlEmh4lHig/zh-cn_image_0000002194010448.png?HW-CC-KV=V1&HW-CC-Date=20261102T125903Z&HW-CC-Expire=31536000000&HW-CC-Sign=CE20974D8E2429797B59F9F361CC9ECF2446ED29CFAE7E7081D58058F247BCBE)

## 示例代码

* [基于后台任务实现应用流畅体验](https://gitcode.com/harmonyos_samples/BackTaskImplement)

