应用内电量与系统电量显示不一致
===============

#### 问题现象

应用右下角显示的电量与系统电量存在较大差异。例如，当手机系统显示电量为95%时，应用内部却显示约为30%。

#### 背景知识

*   关于应用中显示电量，需要用到[@ohos.batteryInfo](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-battery-info)模块来实时获取电量，并在页面中展示出来。
    
    batteryInfo主要属性如下：
    
    | 
    名称
    
     | 
    
    类型
    
     | 
    
    可读
    
     | 
    
    可写
    
     | 
    
    说明
    
     |
    | :-- | :-- | :-- | :-- | :-- |
    | 
    
    batterySOC
    
     | 
    
    number
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备剩余电池电量百分比。元服务API： 从API version 12开始，该接口支持在元服务中使用。
    
     |
    | 
    
    chargingStatus
    
     | 
    
    BatteryChargeState
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备电池的充电状态。元服务API： 从API version 12开始，该接口支持在元服务中使用。
    
     |
    | 
    
    healthStatus
    
     | 
    
    BatteryHealthState
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备电池的健康状态。
    
     |
    | 
    
    pluggedType
    
     | 
    
    BatteryPluggedType
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备连接的充电器类型。
    
     |
    | 
    
    voltage
    
     | 
    
    number
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备电池的电压，单位微伏。
    
     |
    | 
    
    technology
    
     | 
    
    string
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备电池的技术型号。
    
     |
    | 
    
    batteryTemperature
    
     | 
    
    number
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备电池的温度，单位0.1摄氏度。
    
     |
    | 
    
    isBatteryPresent
    
     | 
    
    boolean
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备是否支持电池或者电池是否在位。
    
     |
    | 
    
    batteryCapacityLevel
    
     | 
    
    BatteryCapacityLevel
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备电池电量的等级。
    
     |
    | 
    
    nowCurrent
    
     | 
    
    number
    
     | 
    
    是
    
     | 
    
    否
    
     | 
    
    表示当前设备电池的电流，单位毫安。
    
     |
    

*   [COMMON\_EVENT\_BATTERY\_CHANGED](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/commoneventmanager-definitions#common_event_battery_changed)：表示电池充电状态、电平和其他信息发生变化的公共事件的动作。当电池电量、电池电压、电池温度、电池健康状态、设备连接的充电器类型、充电器最大电流、充电器最大电压、电池充电状态、充电次数、电池的总容量、电池剩余容量、电池的技术型号、当前电池的电流、电池的充电类型变化时，将会触发事件通知服务发布该系统公共事件。

#### 问题定位

1.  通过全局搜索batteryInfo或batterySOC等关键词，确认哪些页面或组件使用了@ohos.batteryInfo模块来获取设备电量信息。
2.  检查是否有使用setInterval或setTimeOut周期性获取电量信息。
3.  是否在每次获取电量后修改应用内电量数据。需要在getBatteryInfo()调用后，将batterySOC的值传递给页面组件进行渲染。

#### 分析结论

应用内部电量显示仅在页面初始化时获取一次，未随系统电量变化而动态更新，导致显示结果与实际系统电量不一致。

#### 修改建议

为了使应用内部电量显示与系统电量保持一致，建议应用通过动态订阅系统的公共事件来监听电量信息的变化。

具体实现可参考以下代码：

import { batteryInfo, BusinessError, commonEventManager } from '@kit.BasicServicesKit';

@Entry
@Component
struct ScanLoopPage2 {
  @State batterySOC: string = '';
  _// 用于保存创建成功的订阅者对象，后续使用其完成订阅及退订的动作_
  private subscriber: commonEventManager.CommonEventSubscriber | null = null;
  _// 订阅者信息_
  private subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
    events: \['usual.event.BATTERY\_CHANGED'\]
  };

  private sub() {
   _ // 创建订阅者回调_
    commonEventManager.createSubscriber(this.subscribeInfo,
      (err: BusinessError, data: commonEventManager.CommonEventSubscriber) => {
        if (err) {
          console.error(\`Failed to create subscriber. Code is ${err.code}, message is ${err.message}\`);
          return;
        }
        console.info('Succeeded in creating subscriber.');
        this.subscriber = data;
        _// 订阅公共事件回调_
        commonEventManager.subscribe(this.subscriber,
          (err: BusinessError) => {
            if (err) {
              console.error(\`Failed to subscribe common event. Code is ${err.code}, message is ${err.message}\`);
              return;
            }
            this.batterySOC = \`电量${batteryInfo.batterySOC}%\`;
            console.info('监听到一次电池状态变化');
          });
      });
  }

  private unSub() {
    if (this.subscriber !== null) {
      commonEventManager.unsubscribe(this.subscriber, (err: BusinessError) => {
        if (err) {
          console.error(\`Failed to unsubscribe. code is ${err.code}, message is ${err.message}\`);
        } else {
          console.info(\`Succeeded in unsubscribing.\`);
          this.subscriber = null;
        }
      });
    }
  }

  aboutToAppear(): void {
    _// 在合适的生命周期中开始订阅公共事件_
    this.batterySOC = \`电量${batteryInfo.batterySOC}%\`;
    console.info(\`当前电量：${batteryInfo.batterySOC}%\`);
    this.sub();
  }

  aboutToDisappear(): void {
    _// 在相应的生命周期回调中取消订阅，防止内存泄漏_
    this.unSub();
  }

  build() {
    Column({ space: 20 }) {
      _// 显示当前电量状态_
      Text(this.batterySOC)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .textAlign(TextAlign.Center)
        .margin({ top: 20 });
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .backgroundColor('#f0f0f0');
  }
}