Disabling Broadcast Receivers

To preserve the battery, applications should avoid executing code that serves no purpose. In the example above, updating the TextView's text when the user interface is not in the foreground is of little value and will only draw power from the battery unnecessarily.

In addition to the ACTION_BATTERY_CHANGED sticky intent containing the battery information shown above, Android defines four more broadcast intents your application can use:

  • ACTION_BATTERY_LOW
  • ACTION_BATTERY_OKAY
  • ACTION_POWER_CONNECTED
  • ACTION_POWER_DISCONNECTED

While you could not receive the ACTION_BATTERY_CHANGED broadcast intent by simply declaring a receiver in your application's manifest (this receiver has to be registered explicitly with a call to registerReceiver()), these other intents allow you to register the receivers in your application's manifest file, as shown in Listing 7–2.

Listing 7–2. Declaring Broadcast Receiver In Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.apress.proandroid.ch07"android:versionCode="1"
android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".BatteryInfoActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".BatteryReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BATTERY_LOW" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.BATTERY_OKAY" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.ACTION_POWER_CONNECTED"
/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"
/>
            </intent-filter>
        </receiver>

    </application>
</manifest>

A simple implementation of the broadcast receiver is shown in Listing 7–3. Here we define a single BatteryReceiver broadcast receiver that is responsible for handling all four actions.

Listing 7–3. BatteryReceiver Implementation

public class BatteryReceiver extends BroadcastReceiver {
    private static final String TAG = "BatteryReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        String text;

        // the four actions are processed here

        if (Intent.ACTION_BATTERY_LOW.equals(action)) {
            text = "Low power";
        } else if (Intent.ACTION_BATTERY_OKAY.equals(action)) {
            text = "Power okay (not low anymore)";
        } else if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
            text = "Power now connected";
        } else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
            text = "Power now disconnected";
        } else {
            return;
        }

        Log.i(TAG, text);
        Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
    }
}

As it is now, the application can be considered to have a serious flaw. As a matter of fact, the application will start (if it is not started already) whenever one of these four actions occurs. While this may be the desired behavior, in many cases you may want your application to behave differently. In this case for example, we can argue it only makes sense to show the Toast messages when the application is the foreground application, as the Toast messages would actually interfere with other applications should we always show them, therefore worsening the user experience.

When the application is not running or is in the background, let's say we want to disable these Toast messages. There are basically two ways to do this:

  • We can add a flag in the application that is set to true in the activity's onResume() and set to false in onPause(), and modify the receiver's onReceive() method to check that flag.
  • We can enable the broadcast receiver only when the application is the foreground application.

While the first approach would work fine, it would not prevent the application from being started whenever one of the four actions triggers. This would ultimately result in unnecessary instructions being executed, which would still draw power from the battery for what is essentially a no-op. Besides, you may have to modify that flag in multiple files should your application define several activities.

The second approach is much better as we can guarantee instructions are executed only when they serve an actual purpose, and therefore power will be drawn from the battery only for a good reason. To achieve this, there are two things we need to do in the application:

  • The broadcast receiver needs to be disabled by default.
  • The broadcast receiver needs to be enabled in onResume() and disabled again in onPause().

Disabling and Enabling the Broadcast Receiver

Listing 7–4 shows how to disable the broadcast receiver in the application's manifest file.

Listing 7–4. Disabling Broadcast Receiver In Manifest

        …
        <receiver android:name=".BatteryReceiver" android:enabled="false">
        …

NOTE: The <application> element has its own enabled attribute. The broadcast receiver will be enabled when both the application and receiver attributes are set to true, and will be disabled when either one of them is set to false.

Listing 7–5 shows how to enable and disable the broadcast receiver in onResume() and onPause().

Listing 7–5. Enabling and Disabling Broadcast Receiver

public class BatteryInfoActivity extends Activity {

    …

    private void enableBatteryReceiver(boolean enabled) {
        PackageManager pm = getPackageManager();
        ComponentName receiverName = new ComponentName(this, BatteryReceiver.class);
        int newState;

        if (enabled) {
            newState = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
        } else {
            newState = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
        }

        pm.setComponentEnabledSetting(receiverName, newState, PackageManager.DONT_KILL_APP);
    }

    …

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mBatteryChangedReceiver);

        enableBatteryReceiver(false); // battery receiver now disabled

        // unregistering the receivers when the application is not in the foreground
saves power
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mBatteryChangedReceiver == null) {
            createBatteryReceiver();
        }
        registerReceiver(mBatteryChangedReceiver, new
            IntentFilter(Intent.ACTION_BATTERY_CHANGED));

        enableBatteryReceiver(true);// battery receiver now enabled
    }

    …
}

Enabling broadcast receivers only when they are really needed can make a big difference in power consumption. While this is an aspect that can be easily overlooked when developing an application, special attention should be given to receivers so that they are enabled only when required.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.102.198