关闭Broadcast Receiver

为了保存电量,应用应该避免执行无目的的代码。在上面的实例中,当用户界面不在最前的时候去更新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给出了broadcast receiver的一个简单实现。我们定义了一个BatteryReceiver处理所有的四个action。

Listing 7-3 BatteryReceiver实现

public class BatteryReceiver extends BroadcastReceiver {private static final String TAG = "BatteryReceiver";@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();String text;// 在这里处理4个actionif (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();}
}

就像现在,应用可以被认为有一个严重的缺陷。事实上,其中任何一个action发生应用将启动(如果还没有start ready)当。尽管这可能是设计行为,在许多情况下可能需要的行为不同。比如在这个情况下,我们可以说只有当应用在最前的时候显示toast有意义,总是显示的话可能会干扰其他应用,使得用户体验变差。
当应用没有在运行,或者在后台运行,我们希望关闭这些Toast。两种方式去实现:
(1) 可以在应用中添加一个标志位,在activity的onResume里面设置为True,在onPause()设置为false,修改receicer的onReceive()方法去检测这个标志
(2) 我们可以仅当应用是foreground应用的时候开启broadcast receiver
尽管第一种方式工作的很好,不会阻止应用从四种Action触发的时候启动。这最终导致没有必要的指令被执行,依然会从电池提取电量。另外,你需要在多个文件里面修改这个标志,因为你的应用会定义多个activity。
第二种方法更好一些,我们可以保证指令仅当我们有一个明确的目的时候去执行,因此电量仅为了合理的理由消耗。为了达到这个目的,我们需要在应用中做两件事:
(1) 默认关闭receiver
(2) 在onResume()开启receiver并且在onPause()关闭

关闭和开启Broadcast Receiver

Listing 7-4显示了如何在应用的manifest文件中关闭broadcast receiver。
Listing 7-4 在Manifest中关闭Broadcast Receiver

...
<receiver android:name=".BatteryReceiver" android:enable="false" >
...

NOTE:<application>标签有自己的enabled属性。broadcast receiver仅在application和receiver的enabled属性都为true的时候才会开启,其他的情况下关闭。

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);}...@Overrideprotected void onPause() {super.onPause();unregisterReceiver(mBatteryChangedReceiver);enableBatteryReceiver(false);  // 关闭battery receiver// 当应用没在前台为了保存电能注销receiver}@Overrideprotected void onResume() {super.onResume();if (mBatteryChangedReceiver == null) {createBatteryReceiver();}registerReceiver(mBatteryChangedReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));enableBatteryReceiver(true);  // 开启battery receiver}...}

仅在确实需要的时候开启broadcast receiver在电能消耗上有很大的不同。尽管这是开发的时候很容易忽视的一个方面,需要特别注意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();}
} 

NOTE: 应用需要ACCESS_NETWORK_STATE权限去获取网络信息。

因为聚焦于最大化电池使用时间,我们需要注意到如下事情:
(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 {// 兑现设置不传输数据}
}

因为这是一个自愿的检测,你的应用实际上可能忽略这个设置,在任何情况下传输数据。然而,因为这可能和用户的意愿抵触,潜在的降低前台数据传输的速度,并且影响电池使用时间,这样的行为可能导致用户卸载掉你的应用。
为了当后台的数据设置改变的时候接到通知,可以在Java代码中注册一个receiver,使用ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED去构建intent filer或者在应用的manifest文件使用andoird.net.conn.BACKGOUND_DATA_SETTING_CHANGED。因为这个设置控制后台数据传输,实际上比在onResume()开启receiver和在onPause()关闭receiver更有意义。

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运行在越来越多的设备上,从手机到平板,从机顶盒到网络笔记本,为所有这些设备产生资源很乏味。然而,使用合适的资源可以大幅增加电池的寿命,因此使你的应用更加合意。除了保存电能,更快的下载和上传将使你的应用响应更好。

精通安卓性能优化-第七章(二)相关推荐

  1. 精通安卓性能优化-第五章(三)

    Concurrency 在java.util.concurrent.atomic和java.util.concurrent.locks包中定义了更多的类.java.util.concurrent.at ...

  2. asp.net程序性能优化的七个方面

    asp.net程序性能优化的七个方面 一.数据库操作 1.用完马上关闭数据库连接 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器 ...

  3. 《C++应用程序性能优化::第五章动态内存管理》学习和理解

    <C++应用程序性能优化::第五章动态内存管理>学习和理解 说明:<C++应用程序性能优化> 作者:冯宏华等 2007年版. 2010.8.29 cs_wuyg@126.com ...

  4. 安卓性能优化之启动优化

    安卓性能优化之启动优化 两个定律 2-5-8原则 八秒定律 启动方式 冷启动 热启动 温启动 启动耗时统计 系统日志 adb命令 启动耗时分析 CPU Profile 工具介绍 使用方式 数据分析 C ...

  5. Java 程序性能优化《第一章》Java性能调优概述 1.4小结

    Java 程序性能优化<第一章>1.4小结 通过本章的学习,读者应该了解性能的基本概念及其常用的参考指标.此外,本章还较为详细的介绍了与性能调优相关的两个重要理论--木桶原理以及Amdah ...

  6. c语言实验7字符串,C语言实验六(第七章二维数组字符串数组)

    C语言实验六(第七章二维数组字符串数组) 第 1 页 共 7 页第七章二维数组.字符串数组题[书面作业] 以书面作业形式上交,2010 年 11 月 1 日课堂交三道题的源程序1. 编写一个主函数:用 ...

  7. SQL Server 查询性能优化——覆盖索引(二)

    在SQL Server 查询性能优化--覆盖索引(一)  中讲了覆盖索引的一些理论. 本文将具体讲一下使用不同索引对查询性能的影响. 下面通过实例,来查看不同的索引结构,如聚集索引.非聚集索引.组合索 ...

  8. Android性能优化(第二章)

    这章就当填坑了,姑且也算是性能优化吧 ⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄ 0x00 集合处理 对一些list和数组的操作其实Java已经帮我们做了不少功课了,回想起来在一些使用场景中笔者还傻乎乎的写一堆f ...

  9. MYSQL性能优化详解(二)

    接着上一篇学习:http://www.cnblogs.com/quanzhiguo/p/6401453.html 七.MySQL数据库Schema设计的性能优化 高效的模型设计 适度冗余-让Query ...

最新文章

  1. Python中的retry
  2. 窄行打印纸打印机规格_电脑打印纸的尺寸和打印机纸张规格的设置
  3. 基于Python预测股价的那些人那些坑,请认真看完!
  4. TypeScript 工具类型 - Utility Types
  5. 使用.NetCore 控制台演示 熔断 降级(polly)
  6. IOS学习笔记二十一(NSDictionary、NSMutableDictionary)
  7. event auto模式的问题
  8. python pandas 日期_python+pandas+时间、日期以及时间序列处理方法
  9. 华为已开始生产不含美国零部件的5G基站
  10. 第二节20181110
  11. 按群计数10以内_10米12米60吨地磅扬州地磅数字地磅厂-鹰衡称重
  12. 微信小程序商城完整代码
  13. win10服务器怎么连接显示器不亮,Win10检测不到第二个显示器怎么解决?Win10外接显示器黑屏解决方法...
  14. transition动画
  15. GPA计算器雏形--
  16. 阿里云云计算专业认证考试(Alibaba Cloud Certified Professional,ACP)
  17. mac常见问题(五) Mac 无法开机
  18. 我的Python分析成长之路9
  19. iOS 扫描二维码/条形码
  20. Linux的chmod命令

热门文章

  1. Python爬虫——使用正则表达式爬取西安7天的天气预报,并使用prettytable模块输出
  2. WinPhone开发之GeoCoordinateWatcher
  3. C#开发--ASP.NETweb开发初探
  4. 一文读懂自动驾驶运行设计域ODD
  5. 从零开始学习信号完整性(SIPI)--8 电平标准
  6. 国能常发移动应用问题处理
  7. 深度学习:可视化-结果loss acc可视化及测试数据显示
  8. STM32 CCM内存使用
  9. ——————【 正则表达式 】——————
  10. Android禁止WebView返回时刷新