Cómo supervisar el nivel de batería y el estado de carga

Cuando modificas la frecuencia de las actualizaciones en segundo plano para reducir el efecto de las actualizaciones en la duración de la batería, te recomendamos que comiences por comprobar el estado de carga y el nivel actual de la batería.

El impacto en la duración de la batería de las actualizaciones de aplicaciones depende del nivel de batería y del estado de carga del dispositivo. Cuando el dispositivo está conectado a la corriente, el impacto es insignificante, por lo que, en la mayoría de los casos, puedes maximizar la frecuencia de actualización siempre que el dispositivo esté conectado a un cargador de pared. Por el contrario, si el dispositivo se está descargando, reducir la frecuencia de actualización te ayudará a prolongar la duración de la batería.

Del mismo modo, puedes verificar el nivel de carga de la batería y reducir la frecuencia de las actualizaciones (o incluso detenerlas) cuando la batería esté a punto de agotarse.

Cómo determinar el estado de carga actual

En primer lugar, determina el estado de carga actual. El BatteryManager envía los detalles de carga y de la batería en un Intent persistente que incluye el estado de carga.

Como se trata de un intent persistente, no necesitas registrar un BroadcastReceiver; con solo llamar a registerReceiver y pasar null como el receptor, como se muestra en el siguiente fragmento, se muestra el intent de estado actual de la batería. Puedes pasar un objeto BroadcastReceiver real aquí, pero nos encargaremos de las actualizaciones en una sección posterior, por lo que no es necesario.

Kotlin

val batteryStatus: Intent? = IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
    context.registerReceiver(null, ifilter)
}

Java

IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter);

Puedes extraer el estado de carga actual y, si el dispositivo se está cargando, puedes ver si se está usando un cargador de CA o USB:

Kotlin

val status: Int = batteryStatus?.getIntExtra(BatteryManager.EXTRA_STATUS, -1) ?: -1
val isCharging: Boolean = status == BatteryManager.BATTERY_STATUS_CHARGING
        || status == BatteryManager.BATTERY_STATUS_FULL

// How are we charging?
val chargePlug: Int = batteryStatus?.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) ?: -1
val usbCharge: Boolean = chargePlug == BatteryManager.BATTERY_PLUGGED_USB
val acCharge: Boolean = chargePlug == BatteryManager.BATTERY_PLUGGED_AC

Java

// Are we charging / charged?
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                     status == BatteryManager.BATTERY_STATUS_FULL;

// How are we charging?
int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;

Por lo general, debes maximizar la frecuencia de las actualizaciones en segundo plano en el caso de que el dispositivo esté conectado a un cargador de CA, reducirla si la carga es mediante USB y reducirla aún más si la batería se está descargando.

Cómo supervisar los cambios en el estado de carga

El estado de carga puede cambiar tan fácilmente como se puede conectar un dispositivo, por lo que es importante supervisarlo para detectar cambios y modificar la frecuencia de actualización según corresponda.

El BatteryManager transmite una acción cada vez que el dispositivo se conecta o desconecta de la corriente. Es importante recibir estos eventos incluso cuando la app no se está ejecutando (especialmente porque estos eventos deben afectar la frecuencia con la que inicias tu app para iniciar una actualización en segundo plano). Por lo tanto, debes registrar un BroadcastReceiver en tu manifiesto para escuchar ambos eventos definiendo ACTION_POWER_CONNECTED y ACTION_POWER_DISCONNECTED en un filtro de intents.

<receiver android:name=".PowerConnectionReceiver">
  <intent-filter>
    <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
    <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
  </intent-filter>
</receiver>

Cómo determinar el nivel de batería actual

En algunos casos, también es útil determinar el nivel de batería actual. Puedes reducir la frecuencia de las actualizaciones en segundo plano si el nivel de carga de la batería es inferior a un valor determinado.

Para encontrar la carga actual de la batería, extrae el nivel y la escala actuales de la batería del intent de estado de la batería, como se muestra a continuación:

Kotlin

val batteryPct: Float? = batteryStatus?.let { intent ->
    val level: Int = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
    val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
    level * 100 / scale.toFloat()
}

Java

int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);

float batteryPct = level * 100 / (float)scale;

Reacciona a los cambios significativos en el nivel de la batería

No es fácil controlar continuamente el estado de la batería, pero tampoco es necesario.

En términos generales, el impacto de supervisar el nivel de batería tiene un mayor impacto en la batería que el comportamiento normal de tu app. Por ejemplo, si registras un BroadcastReceiver en el manifiesto para cancelar el trabajo pendiente cuando la batería está baja, la principalmente servirá para agotar aún más la batería (y, por lo tanto, imposible desde Android 8.0). En su lugar, puedes proporcionar restricciones sobre el trabajo que describan cuándo se debe ejecutar, lo que permite que el sistema tome una decisión sin consumir energía para iniciar tu app.

Cuando el nivel de batería esté muy bajo, te recomendamos que no ejecutes las actualizaciones en segundo plano. Si el teléfono se apaga antes de que puedas usarlos, no importa qué tan actualizados estén los datos. Para ello, usa la biblioteca de WorkManager con una restricción BatteryNotLow a fin de especificar que el trabajo no se debe ejecutar si tiene poca batería (además de las restricciones de NetworkType relevantes).

En muchos casos, el hecho de cargar un dispositivo coincide con la acción de utilizar un conector. En la siguiente lección, se muestra cómo determinar el estado actual del conector y cómo supervisar los cambios en la conexión del dispositivo.