很多朋友都抱怨Android机电量不行,没有iPhone的耐用,问我怎么解决。我首先恭喜你们拥有一颗发现的眼睛,电量不耐用是Android的通病。明明电量是iPhone的几倍,但是可能还没有它耐用,为什么?究其原因,就是Android手机本身系统和ios的系统是不一样的(因为没有开发手机驱动的经验,所以粗略提一下带过)。作为一个Android开发人员,如果都能到更好的电量优化,相信你的手机电量会更加耐用。
Android应用开发中存在很多比较耗电的特性。例如网络,定位,传感器等,同时关于一些关键的API的正确使用也是有效降低应用耗电的手段,例如BroadcastReceiver,AlarmManager,WakeLock等。
1. BroadcastReceiver
为了减少应用的损耗的电量,在代码实现中需要尽量避免无用操作代码的执行。当应用退到后台,一切的界面刷新都是没有意义而且浪费内存和电量的,广播接收器是一个典型的例子。如果应用中存在一个监听网络状态变化的广播接收器并会执行一些动作,例如弹出Toast提示用户网络环境的切换,那么当应用位于后台时,我们需要禁用掉这个提示功能,因为这时它不仅影响用户使用其他应用而且孩子啊后台默默地消耗着设备上本来就不多的电量,通常的做法是在界面onPause之后取消广播接收器的监听操作,同时根据具体业务需求选择当应用位于后台时是否禁用广播接收器,代码如下:
/**
* 是否禁用广播接收器
* @param isEnabled
* @param receiver
*/
private void enableBroadcastReceiver(boolean isEnabled,Class<?> receiver) {
PackageManager pm = getPackageManager();
ComponentName receiverName = new ComponentName(this,receiver);
int newState;
if(isEnabled) {
newState = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
} else {
newState = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
}
pm.setComponentEnabledSetting(receiverName,newState,PackageManager.DONT_KILL_APP);
}
2. 数据传输
Android 中的数据传输方式有很多种,常见的有:
- 蓝牙传输
- Wi-Fi 传输
- 移动网络传输
无论哪种传输方式,为了更好地延长电池的使用时间,我们在使用过程中都需要重点关注两件事情
后台数据传输的管理:根据具体业务需求,严格限制应用位于后台时是否禁用某些数据传输,尽量能够避免无效的数据传输。
数据传输的频度问题:通过经验值或者数据统计的方法确定好数据传输的频度,避免冗余重复的数据传输,同时,数据传输过程中要压缩数据大小,合并网络请求,避免轮询等。
3. 位置服务
Android中常见的位置服务有两种:GPS定位和网络定位。GPS定位服务需要ACCESS_FINE_LOCATION权限,网络定位服务需要ACCESS_COARSE_LOCATION或者ACCESS_FINE_LOCATION权限。代码中使用位置服务时,通常需要关注一下几个方面。
- 有没有及时注销位置监听器:和使用广播监听器一样,位置监听器也需要做到及时的注销,因为长时间的监听位置更新会耗费大量的电量,通常可以选择在页面的onPause中进行注销操作,更好用且全局有效的做法是禁用位置监听器,代码如下:
private void disableLocaltionListener (LocationListener listener) {
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
locationManager.removeUpdates(listener);
}
位置更新监听频率的设定:根据具体的业务需求设置一个合适的更新频率值,通常需要在定位精度和耗电量之间综合考虑。Android SDK 提供了requestLocationUpdates 方法进行设置,这个方法有两个主要参数
- minTime:用来指定位置更新通知的最小时间间隔,单位是毫秒。
- minDistance:用来指定位置更新通知的最小距离,单位是米。
多种位置服务的选择:Android系统为开发者提供了三种定位服务。
- GPS定位:通过接受全球定位系统的卫星提供的经纬度坐标信息实现位置服务,精度是最高的,通常在10米以内。当然,GPS定位在时间和电量的消耗上也是最高的。
- 网络定位:通过移动通信的基站信号差异来计算出手机所在的位置,精度比GPS定位差很多,通常在几百米范围内。
- 被动定位:最省电的定位服务,如果应用使用被动定位服务,说明它想知道位置更新信息但又不想主动请求获取,也就是这个应用会等待手机中其他应用,服务或者系统组件发出定位请求,并和这些组件的监听器一起接收位置更新。
实际开发中需要综合考虑应用的具体需求在不同时机采用不同的定位服务,实际开发中很多会选择第三方的定位SDK,例如:百度定位,高德定位。因为这些SDK无论在定位时间,定位精度还是定位耗电量方面都作了专门的优化。
4. AlarmManager
AlarmManager是Android SDK提供的一个唤醒API,它是系统级别的服务,可以在特定的时刻广播一个特定的Intent,这个PendingIntent可以用来启动Activity,Service或BroadcastReceive。例如后台上传统计信息,可以通过一个AlarmManager来定时检查是否满足条件并上传记录。AlarmManager提供了三个常用的方法。
- set:设置一次性的闹钟操作
- setRepeating:设置重复性的闹钟操作
- setInexactRepeating:也是设置重复性的闹钟操作,只不过两个相连的闹钟执行的间隔时间不是固定的。
AlarmManager的唤醒操作也是比较耗电的,通常情况下需要保证两次唤醒操作的时间间隔不要太短,在不需要使用唤醒功能的情况下尽早取消AlarmManager,否则应用会一直处于耗电状态。
5. WakeLock
WakeLock是为了保持设备处于唤醒状态的API,因为在某些情况下,即使用户长时间不与设备交互,仍然需要阻止设备进入休眠状态,从而保证良好的用户体验。WakeLock的锁类型又很多种,不同的锁类型对CPU,屏幕和键盘的影响不相同,具体情况如下:
- PARTIAL_WAKE_LOCK:保持CPU正常运转,但屏幕和键盘灯可能是关闭的。
- SCREEN_DIM_WAKE_LOCK:保持CPU正常运转,允许屏幕点亮但可能是置灰的,键盘灯可能是关闭的。
- SCREEN_BRIGHT_WAKE_LOCK:保持CPU正常运转,允许屏幕高度显示,键盘灯可能是关闭的。
- FULL_WAKE_LOCK:保持CPU正常运转,保持屏幕高亮显示,键盘灯也保持亮度。
- ACQUIRE_CAUSES_WAKEUP:强制屏幕和键盘灯亮起,这种锁针对一些必须通知用户的操作。
- ON_AFTER_RELEASE:当WakeLock被释放后,继续保持屏幕和键盘灯开启一定时间。
WakeLock的使用很简单,语句如下:
PowerManager.WakeLock wakeLock = null;
// 获取唤醒锁
private void acquireWakeLock() {
if(null == wakeLock) {
PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,"PlayService");
if(null != wakeLock) {
wakeLock.acquire();
}
}
}
// 释放唤醒锁
private void releaseWakeLock() {
if(null != wakeLock) {
wakeLock.release();
wakeLock = null;
}
}
使用WakeLock时,需要切记及时释放锁,有的应用在使用完WakeLock之后会忘记释放它,从而导致屏幕一直显示很长时间,快速的耗费了手机的电量。通常情况下,我们要尽早地释放WakeLock,例如在播放视频时获取WakeLock保持屏幕常亮,在暂停播放时就应该及时地释放锁,而不是等到停止播放才释放,在应用恢复播放时再次获取WakeLock即可。
6. Thanks
《Android高级进阶》——顾浩鑫