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:
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.
<?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.
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:
true
in the activity's onResume()
and set to false
in onPause()
, and modify the receiver's onReceive()
method to check that flag.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:
onResume()
and disabled again in onPause()
.Listing 7–4 shows how to disable the broadcast receiver in the application's manifest file.
…
<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()
.
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.
3.142.12.207