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

Quando a frequência das atualizações em segundo plano é alterada para reduzir o efeito dessas atualizações 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 aplicativos 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á conectado a uma fonte de alimentação é insignificante e, na maioria dos casos, você pode maximizar a taxa de atualização sempre que o dispositivo estiver conectado a um carregador de parede. Por outro lado, se o dispositivo estiver descarregando, a redução da taxa de atualização ajudará a prolongar a duração da bateria.

Da mesma forma, será possível conferir o nível de carregamento 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 um Intent persistente que inclui o status de carregamento.

Por ser um intent persistente, não é preciso registrar um BroadcastReceiver. Ao simplesmente chamar registerReceiver passando null como receptor, como mostrado no próximo snippet, o intent de status atual da bateria é retornado. Você pode passar um objeto BroadcastReceiver real aqui, mas isso não é necessário, porque 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);
    

Você poderá extrair o estado de carregamento atual e, se o dispositivo estiver sendo carregado, saber se isso está sendo feito via USB ou carregador de parede:

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 quando o dispositivo está conectado a um carregador de parede, reduzir a taxa se for via USB e diminuir ainda mais se a bateria estiver descarregando.

Monitorar alterações no estado de carregamento

O estado de carregamento pode mudar tão facilmente quanto a conexão de um dispositivo. Por isso, é importante monitorar as mudanças no estado de carregamento e alterar adequadamente a taxa de atualização.

O BatteryManager transmitirá uma ação sempre que o dispositivo for conectado ou desconectado da fonte de energia. É importante receber esses eventos mesmo que o app não esteja em execução, principalmente porque eles afetam a frequência de inicialização do app para iniciar uma atualização em segundo plano. Então, é preciso registrar um BroadcastReceiver no seu manifesto para detectar os dois eventos, definindo ACTION_POWER_CONNECTED e ACTION_POWER_DISCONNECTED dentro de 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 pela redução da taxa de atualizações em segundo plano se a carga da bateria estiver abaixo de determinado nível.

A carga atual da bateria pode ser encontrada extraindo o nível e a escala atual do intent de estado dela, como mostrado aqui:

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 / scale.toFloat()
    }
    

Java

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

    float batteryPct = level / (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.

Em termos gerais, o impacto do monitoramento constante do nível da bateria é maior na bateria do que no comportamento normal do app. Uma prática recomendada é monitorar somente alterações significativas no nível da bateria, especialmente quando o dispositivo entra ou sai de um estado de bateria baixa.

O snippet do manifesto abaixo foi extraído do elemento do filtro de intent dentro de um broadcast receiver. O receiver é acionado sempre que a bateria do dispositivo fica baixa ou sai dessa condição ao detectar 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, recomenda-se desativar todas as atualizações em segundo plano quando a bateria estiver criticamente baixa. Não importa se 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 lição a seguir mostra como determinar o estado de ancoragem atual e monitorar alterações na ancoragem do dispositivo.