Monitorar o nível de bateria e o estado de carregamento

Quando você muda a frequência das atualizações em segundo plano para reduzir o efeito delas na duração da bateria, é recomendável verificar o nível atual da bateria e o estado de carregamento.

O impacto na duração da bateria devido à execução de atualizações de apps depende do nível da bateria e do estado de carregamento do dispositivo. O impacto da execução de atualizações enquanto o dispositivo está carregando via CA é insignificante. Portanto, na maioria dos casos, você pode maximizar a taxa de atualização sempre que o dispositivo está conectado a um carregador de parede. Por outro lado, se o dispositivo estiver descarregando, a redução da taxa de atualização vai ajudar a prolongar a duração da bateria.

Da mesma forma, será possível verificar o nível de carga da bateria, reduzindo potencialmente a frequência de (ou até mesmo interrompendo) as atualizações quando a carga da bateria estiver quase acabando.

Determinar o estado de carregamento atual

Comece determinando o status de carregamento atual. O BatteryManager transmite todos os detalhes da bateria e do carregamento em uma Intent fixa que inclui o status de carregamento.

Por ser uma intent fixa, você não precisa registrar um BroadcastReceiver. Basta chamar registerReceiver transmitindo null como o receptor, conforme mostrado no próximo snippet, para que a intent de status da bateria atual seja retornada. É possível transmitir um objeto BroadcastReceiver real aqui, mas isso não é necessário, mas abordaremos as atualizações em uma seção posterior.

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);

É possível extrair o status de carregamento atual e, se o dispositivo estiver sendo carregado, se ele está sendo carregado via USB ou CA:

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;

Normalmente, é necessário maximizar a taxa de atualizações em segundo plano no caso em que o dispositivo está conectado a um carregador de parede, reduzir a taxa se a carga for via USB e diminuir ainda mais se a bateria estiver descarregando.

Monitorar mudanças no estado de carregamento

O status de carregamento pode mudar com a mesma facilidade que um dispositivo pode ser conectado. Por isso, é importante monitorar as mudanças no estado de carregamento e mudar a taxa de atualização.

O BatteryManager transmite uma ação sempre que o dispositivo é conectado ou desconectado da energia. É importante receber esses eventos mesmo quando o app não está em execução, principalmente porque eles afetam a frequência com que você inicia o app para iniciar uma atualização em segundo plano. Portanto, registre um BroadcastReceiver no manifesto para detectar os dois eventos definindo ACTION_POWER_CONNECTED e ACTION_POWER_DISCONNECTED em um filtro de intent.

<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>

Determinar o nível atual da bateria

Em alguns casos, também é útil determinar o nível atual da bateria. Você poderá optar por reduzir a taxa das atualizações em segundo plano se a carga da bateria estiver abaixo de um determinado nível.

Você pode encontrar a carga atual da bateria extraindo o nível e a escala atuais da intent de status da bateria, conforme mostrado a seguir:

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;

Monitorar alterações significativas no nível da bateria

Não é fácil monitorar continuamente o estado da bateria, mas não é preciso fazer isso.

De modo geral, o impacto do monitoramento constante do nível da bateria tem um impacto maior na bateria do que o comportamento normal do app. Portanto, é recomendável monitorar apenas mudanças significativas no nível da bateria, especificamente quando o dispositivo entra ou sai de um estado de bateria fraca.

O snippet de manifesto abaixo é extraído do elemento de filtro de intent em um broadcast receiver. O receptor é acionado sempre que a bateria do dispositivo fica baixa ou sai dessa condição detectando ACTION_BATTERY_LOW e ACTION_BATTERY_OKAY.

<receiver android:name=".BatteryLevelReceiver">
  <intent-filter>
    <action android:name="android.intent.action.BATTERY_LOW"/>
    <action android:name="android.intent.action.BATTERY_OKAY"/>
  </intent-filter>
</receiver>

Em geral, é recomendável desativar todas as atualizações em segundo plano quando a bateria está criticamente baixa. Não importa se os seus dados estão atualizados se o smartphone desligar antes que você possa usá-lo.

Em muitos casos, o ato de carregar um dispositivo coincide com colocá-lo em uma base. A próxima lição mostra como determinar o estado atual da base e monitorar mudanças na base de dispositivo.