赞
踩
为了保存电量,应用应该避免执行无目的的代码。在上面的实例中,当用户界面不在最前的时候去更新Textview的text是没有价值的,仅仅无必要的从电池提取能量。
除了ACTION_BATTERY_CHANGED的sticky intent包含电池信息,Android定义了其他的四个intent,你的应用可以使用:
(1) ACTION_BATTERY_LOW
(2) ACTION_BATTERY_OKAY
(3) ACTION_POWER_CONNECTED
(4) ACTION_POWER_DISCONNECTED
尽管简单的在应用manifest中声明一个receiver,不能收到ACTION_BATTERY_CHANGED的broadcast intent(这个receiver需要显式的在代码中调用registerReceiver()),其他的intent允许在应用的manifest里面注册,如Listing 7-2。
Listing 7-2 在Manifest中声明receiver
- <?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>

Listing 7-3 BatteryReceiver实现
- 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;
-
- // 在这里处理4个action
- 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();
- }
- }

Listing 7-4显示了如何在应用的manifest文件中关闭broadcast receiver。
Listing 7-4 在Manifest中关闭Broadcast Receiver
- ...
- <receiver android:name=".BatteryReceiver" android:enable="false" >
- ...
Listing 7-5给出了如何在onResume()开启和在onPause()关闭broadcast receiver。
Listing 7-5 开启和关闭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
-
- // 当应用没在前台为了保存电能注销receiver
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (mBatteryChangedReceiver == null) {
- createBatteryReceiver();
- }
-
- registerReceiver(mBatteryChangedReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
-
- enableBatteryReceiver(true); // 开启battery receiver
- }
-
- ...
-
- }

许多应用在设备和服务器之间传递数据,或者设备之间传递数据。就像电池状态,应用需要从设备的网络连接获取信息。ConnectivityManager类提供可供应用访问网络信息的API。Android通常有多种数据连接可用:
(1) Bluetooth
(2) Ethernet
(3) Wi-Fi
(4) WiMAX
(5) Mobile(EDGE, UMTS, LTE)
Listing 7-6给出了如何获取活动的链接以及所有的链接的信息。
Listing 7-6 网络信息
- private void showNetworkInfoToast() {
- ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
-
- // 仅仅显示active链接
- NetworkInfo info = cm.getActiveNetworkInfo();
- if (info != null) {
- Toast.makeText(this, "Active: " + info.toString(), Toast.LENGTH_LONG().show();
- }
-
- // 显示所有链接
- NetworkInfo[] array = cm.getAllNetworkInfo();
- if (array != null) {
- String s = "All: ";
- for (NetworkInfo i : array) {
- s += i.toString() + "\n";
- }
- Toast.makeText(this, s, Toast.LENGTH_LONG).show();
- }
- }

因为聚焦于最大化电池使用时间,我们需要注意到如下事情:
(1) 后台数据设置
(2) 数据传输率
用户可以设置指定是否允许后台数据传输,预期可以节省电池电量。如果你的应用不在前台的时候需要数据传输,需要检测标志位,如Listing 7-7所示。 Service通常需要在初始化任何传输前检查这个设置。
Listing 7-7 检测后台数据设置
- private void transferData(byte[] array) {
- ConnectivityManager cm = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
- boolean backgroundDataSetting = cm.getBackgroundDataSetting();
-
- if(backgroundDataSetting) {
- // transfer data
- } else {
- // 兑现设置不传输数据
- }
- }
NOTE:getBackgoundDataSetting()方法在4.0弃用了,会always返回true。另外,当后台数据传输不可用network可能会被断开。
传输率变化范围很广,GPRS数据传输通常少于100K每秒,而LTE或者Wifi连接通常达到几M。除了连接类型,NetworkInfo类还指定了连接的子类型。当连接是TYPE_MOBILE的时候这很重要。Android定义了如下的连接子类型(在TelephonyManager类):
子类型随着新技术创建和开发而添加。比如,LTE子类型在API 11添加,HSPAP子类型在API 13添加。如果你的代码依赖于这些值,保证你处理了这种情况,即应用存在他不知道的数值;否则可能导致应用不能传输数据。当有新的子类型添加,需要更新你的代码,所以请关注每一个版本的Android SDK。改变列表在http://d.android.com/sdk/api_diff/13/changes.html给出,比如。
直观上你的应用应该选择更快的连接。即使3G射频芯片消耗比Wifi射频芯片消耗更少的电量,Wifi传输率可能最终意味着WIFI传输能够减少电量消耗,因为传输可以在很短的时间内完成。
NOTE:因为数据计划现在通常允许有限数量的数据传输(比如,¥30/2GB每月),Wifi连接经常被作为第一选择。同样的,你的应用可以使用NetworkInfo.isRoaming()去了解设备当前是否在漫游,因为这可以添加额外的消费,当isRoaming()返回true的时候,需要避免传输数据。
Table 7-2给出了T-Mobile G1手机不同的组件内存消耗(也叫HTC Dream, or Era G1)。尽管这个手机现在有些老(在2008晚期发布),数值同样给出了每个组件提取多少电量一个很好的概述。
Table 7-2 Android G1手机电能消耗(源自: Google I/O 2009)
尽管精确的数值会随不同设备变化,了解你的应用使用多少电能很重要。因为G1有一个1150mAh的电池,下载和播放视频的应用(比如,YouTube)在使用3G连接的情况下,大约在3个小时清空电池:3G需要150mA,CPU需要90mA,LCD需要90mA,总共330mA,或者3个半小时的使用(假设没有其他应用运行)。
如果你可以控制什么样的数据传输,可以考虑在传输前压缩数据。尽管CPU需要在数据使用前需要解压缩(因此需要更多的电量),数据传输将更快,射频芯片(比如,3G,Wifi)可以更快的关闭,以保存电池的寿命。考虑的事情包括:
(1) 使用GZIP压缩文本数据,使用GZIPInputStream去访问数据
(2) 如果可能使用JPEG而不是PNG
(3) 使用匹配设备分辨率的资源(比如,如果需要resize到96*54,没有必要去下载1920*1080的图片)
传输速度越慢(比如,EDGE),压缩的重要性越大,因为你希望去减少射频芯片开启的时间。
因为Android运行在越来越多的设备上,从手机到平板,从机顶盒到网络笔记本,为所有这些设备产生资源很乏味。然而,使用合适的资源可以大幅增加电池的寿命,因此使你的应用更加合意。除了保存电能,更快的下载和上传将使你的应用响应更好。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。