Battery Consumption Optimization

    image

    Introduction


    This article provides some tips for optimizing battery consumption for applications.
    By disabling background update services when the connection is lost or by reducing the update rate when the battery level is low, you can significantly minimize the impact of the application on the battery.
    Some background services (downloading updates or application content from the network, complex calculations, etc.) are advisable to disable or reduce the frequency of their launch when the battery level is low. For such actions, it is important to take into account several factors, such as, for example, the current state of charging of the device, the presence of a connected docking station or the presence of a connection to the network. Below are ways to get these values ​​and monitor their changes.

    Current charge status


    The BatteryManager class sends information about the level and state of the battery charge in the corresponding intent. In this case, you can register BroadcastReceiver and receive timely information about the status of the battery. And you can get this data one-time without registering the receiver:
    
    IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
    Intent batteryIntent = context.registerReceiver(null, ifilter);
    

    From the received intent, information is taken about the current battery level, about the charging status, and also about charging from the AC network or AC:
    
    public void getBatteryStatus(Intent batteryIntent) {
        // Заряжается ли батарея (или уже заряжена) ?
        int status = batteryIntent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
        boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
                         status == BatteryManager.BATTERY_STATUS_FULL;
        //Каким образом проходит зарядка?
        int chargePlug = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
        boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
        boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;
    }
    

    It is usually worthwhile to maximize the frequency of background updates of the application if the device is charging from the AC mains, reduce if charging is via usb and make it minimal if the device is not in the charging state at all.
    In the same case, when it is necessary to monitor the charging status of the device, you should register in the manifest of the BroadcastReceiver application, which will receive messages about connecting / disconnecting the charger. In this intent-filter, you need to add ACTION_POWER_CONNECTED and ACTION_POWER_DISCONNECTED :

    
    public class PowerConnectionReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) { 
            getBatteryStatus(intent);   
        }
    }
    

    Current battery


    The current relative battery charge can be calculated from the current charge and maximum charge:
    
    int level = battery.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
    int scale = battery.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
    float batteryPct = level / (float)scale;
    

    It is worth mentioning that regular monitoring of the battery status is resource-consuming for the battery itself. Therefore, it is recommended to monitor only certain changes in the charge level, namely the low charge level:

    It is good practice to turn off all background updates or calculations when the battery level becomes low.

    Dock Status and Type


    There are a large number of docking stations for Android devices. For example, an in-car dock or an Asus Transformer keyboard dock. However, most docking stations charge the device itself.
    You can get information about the type and status of the dock from action'a ACTION_DOCK_EVENT . It can be obtained once:
    
    IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
    Intent dockIntent = context.registerReceiver(null, ifilter);
    

    or subscribe to notifications by adding BroadcastReceiver in the manifest and specifying action:

    Information about the dock is obtained as follows:
    
    public void getDockStatus(Intent dockIntent) {
        //определение подключения к доку
        int dockState = dockIntent.getIntExtra(Intent.EXTRA_DOCK_STATE, -1);
        boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
        //определение типа дока
        boolean isCar = dockState == Intent.EXTRA_DOCK_STATE_CAR;
        boolean isDesk = dockState == Intent.EXTRA_DOCK_STATE_DESK || 
                     dockState == Intent.EXTRA_DOCK_STATE_LE_DESK ||
                     dockState == Intent.EXTRA_DOCK_STATE_HE_DESK;
    }
    

    The values EXTRA_DOCK_STATE_HE_DESK and EXTRA_DOCK_STATE_LE_DESK appeared only with API version 11.

    Network Connection Status


    Before performing background updates of the application or long downloads from the network, it is worth checking the connection and its approximate speed. You can use the ConnectivityManager class to do this .

    Definition of internet connection:
    
    ConnectivityManager cm =
            (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    boolean isConnected = activeNetwork.isConnectedOrConnecting();
    

    It is also sometimes worthwhile to determine the type of current connection before starting downloads. This is important because Mobile Internet connection speed is usually lower than Wi-Fi, and the price of traffic is higher.
    
    boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI;
    

    You can subscribe to notifications of changes in connection status by adding BroadcastReceiver to the manifest by specifying the appropriate action:

    Since such changes can occur quite often, it is good practice to monitor these alerts only when updates or downloads have been disabled previously. Usually it’s enough to check the connection before starting the update and in case the connection is missing subscribe to notifications.

    Turn on / off alerts


    It is not recommended that you keep the battery, dock, and connection alerts on all the time because they will wake up the device too often. The best solution is to include alerts only when necessary.
    The PackageManager class allows changing the state of elements declared in the manifest, including turning on / off BroadcastReceivers:
    
    ComponentName receiver = new ComponentName(context, CustomReceiver.class);
    PackageManager pm = context.getPackageManager();
    pm.setComponentEnabledSetting(receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);
    

    Using a similar technique, for example, if the connection is disconnected, only the notification of changes in the state of the network is left on. When a connection appears, you can turn off alerts about network changes and only check for a current connection.
    Similar technology can also be used to delay downloading data from the network until there is a connection with a higher bandwidth, such as Wi-Fi.

    This article is a free translation of a set of tips from the Android Training program for optimizing battery consumption by applications.

    Also popular now: