Contents
优化位置请求对电源的消耗... 1
理解电量消耗... 2
精确率... 2
频率... 2
延迟... 2
位置用例... 3
用户可见的前台更新... 3
知道设备的位置... 3
当用户在特定位置的时候开始更新... 3
基于用户活动状态更新... 3
跟地理位置相关的长期在后台运行的位置更新... 3
没有可见应用组件的长期后台位置更新... 4
当用户与其它应用进行交互时进行高频和高精确率更新... 4
位置实践... 4
移除位置更新... 5
设置超时... 5
批请求... 5
用被动位置更新... 5
优化位置请求对电源的消耗
Android 8.0(API 26)引入的后台位置限制将位置服务的使用是如何影响电源的这个话题重新提出来了。本文介绍了位置服务的最好的用法,目前你可以做什么使得电源更高效。应用这些最好的联系,不管你的应用运行在什么平台,你的应用可以获得好处。
Android 8.0对后台位置访问引入了下面的限制:
- 后台位置统计被禁止了。位置的计算和提交频率一小时限制到几次。
- WiFi扫描变得更不频繁了,当设备一直连接在一个静态接入点时,不计算位置更新。
- Geofencing返回频率从十几秒一次改为约两分钟一次。这些改变明显改善了耗电量,在某些设备上甚至有10多倍的改善。
这里假设你正在使用Google位置服务API,该API比framework位置API精度更高,更省电。本文假设你熟悉fused位置提供API,该API囊括了来自GPS,WiFi,小区网络,加速仪,陀螺仪,指南针和其他传感器的信号。还要熟悉geofencing API,该API基于fused位置服务API,还对电源作了优化。
位置收集和电源消耗直接与下面几方面相关:
- 精确率:位置信息的精确程度。一般精确率越高越耗电。
- 频率:计算位置的频率。计算频率越高越耗电。
- 延迟:提交位置服务的速度。一般延迟越小越耗电。
你可以用setPriority()方法指定位置精确率,传入下面参数之一:
- PRIORITY_HIGH_ACCURACY提供了最精确的位置信息,合并了包括GPS,WiFi,小区和各种传感器的信息,可能会消耗很多电。
- PRIORITY_BALANCED_POWER_ACCURACY同时兼顾了位置精确度和电量消耗。很少用GPS,一般用WiFi和小区广播计算位置信息。
- PRIORITY_LOW_POWER主要基于信号塔,避免使用GPS和WiFi,在最小的耗电量上提供粗略(城市级)的精确度。
- PRIORITY_NO_POWER从其他计算好位置信息的应用中被动接收位置信息。
大多数应用能够用电源平衡或低电消耗的选项来满足。高精确度选项只应用在前台应用或者需要实时位置更新的应用(例如,地图)。
可以用下面两个方法设定位置频率:
- 用setinterval()方法指定你自己的应用计算位置信息的间隙。
- 用setFastestInterval指定其他应用位置计算的结果提交给你的应用的时间间隙。
调用setInterval()时,应该尽量设一个大值。尤其是在后台收集位置信息的应用,因为这部分耗电令人难以接受。几秒的间隔只应该给前台应用使用。Android8.0已经强制这样做了,但是运行在Android7.0和之前版本的应用也应该强制这样。
用setMaxWaitTime()方法设定延迟,一般传入的值是setInterval()参数的几倍。这个设置延迟了位置更新,这样多个位置更新可以捆绑提交。因此而省电。
如果你的应用不需要马上更新位置信息,setMaxWaitTime()越大越好,这样能有效地提高电池效率。
当用geofences时,应用应该尽量传入一个大值给setNotificationResponsiveness()来省电。建议5分钟或更长。
这一段给出了一些典型的位置获取的场景,并对如何使用geofencing和fused位置提供API给出了优化建议。
用户可见的前台更新
例如:地图应用需要不断的精确的低延时的更新。所有更新都在前台:用户启动一个活动,需要位置数据,过一会儿停止该活动。
用setPriority()方法,传入参数PRIORITY_HIGH_ACCURACY或PRIORITY_BALANCED_POWER_ACCURACY。
在setInterval()方法中设定时间间隔是基于:对于实时请求,设为几秒;其他情况,设为几分钟(为了降低耗电,大约设为2分钟或更长)。
知道设备的位置
例如:天气应用,需要知道设备所在位置。
用getLastLocation()方法,这个方法返回上一次得到的位置信息(很少情况下返回null)。这个方法提供了一个获得位置信息的简单的方法,并且不需要联网耗电。和方法isLocationAvailable()一起用,如果isLocationAvailable()返回true,那么getLastLocation()返回的位置信息就很可靠。
当用户在特定位置的时候开始更新
例如:当用户在单位,家获某个特定位置时,请求更新。
用geofencing和fused位置提供者来更新。当应用收到一个进入geofence的激活信号时进行更新;退出genfence是停止更新。这使得用户进入某个特定区域后,能够接收到更多位置更新信息。
这种情况典型的应用场景包括:当进入geofence时贴一个通知,用户点击该通知时,执行更新的代码。
基于用户活动状态更新
例如:当用户正在开车或骑车时请求更新。
用活动识别API和fused位置服务提供者更新。当识别出目标活动时请求更新,停止目标活动时停止更新。
这种情况下典型的场景包括:识别到活动时,贴一个通知,用户点击通知时,提示用户请求更新。
例如:当设备接近某个零售商时,用户想要被提醒。
这是geofencing的一个绝好的例子。因为这个例子几乎100%的包括用addGeofences(GeofencingRequest, PendingIntent)进行后台位置更新。
你应该这样设置配置选项:
- 你如果想跟踪位置变化,用setLoiteringDelay()方法并传入一个大约5分钟或者更短的时间。
- 用setNotificationResponsiveness(),并传入一个大约5分钟的时间。但是,如果应用能够容忍返回值的延时,尽量将时间设置成10分钟。
一个应用同时最多注册大约100个geofence。某些情况下,应用可能希望跟踪更多的零售商,即应用可能需要注册更多的geofence(城市级别)并在大geofence里动态注册更小的geofence。当用户进入一个大geofence时,可以添加小的geofence;当用户退出大geofence时,小geofence可以被移除并重新注册新geofence。
没有可见应用组件的长期后台位置更新
例如:一个被动跟踪位置的应用
注意:考虑一下你是否真正需要后台收集位置信息,因为这样做很耗电。另外,考虑geofencing,因为geofencing API被优化了。
用setPriority()方法,如果可以,用PRIORITY_NO_POWER选项,因为他基本不耗电。如果PRIORITY_NO_POWER不行,考虑用PRIORITY_BALANCED_POWER_ACCURACY或者PRIORITY_LOW_POWER,但对持续后台运行的任务,一定不要用PRIORITY_HIGH_ACCURACY,因为这个选项一直耗电。
如果你需要更多的位置数据,用被动位置更新方法setFastestInterval(),并传入一个相比setInterval()中传入的值更小的值。当与PRIORITY_NO_POWER一起使用时,被动位置信息将会适时地通过其他应用传递过来,而且没有额外消耗。
要想在适中的频率基础上加上一个延时,用setMaxWaitTime()。例如,如果你把setInterval()设成10分钟,那么setMaxWaitTime()大概设到30到60分钟。用这个设置,大约每10分钟,就有一次位置计算,但每30到60分钟才会唤醒应用并有一次批量位置提交。这个方法用一定的延迟争取到了更多数据和低耗电。
当用户与其它应用进行交互时进行高频和高精确率更新
例如: 不管用户关掉屏幕还是在操作另一个应用,导航应用或者运动应用一直工作。
用一个前台服务。如果你的应用将为用户执行一些高消耗的操作,要让用户知道。前台应用需要持续的通知。
这里的实践帮助用户降低耗电。
相当一部分电量消耗是因为当位置更新不再需要的时候却移除失败。这有可能发生,例如,当Activity的onStart()或onResume()中调用了requestLocationUpdates(),但是相应的,在onStop()或者onPause()里却没有调用removeLocationUpdate()。
可以用lifecycle-aware组件避免这问题。
设置超时
为了防止电量泄露,为位置更新请求设置一个超时时间。这个超时时间保证了位置更新不会持续不断的保持,并防止了更新被请求但没被移除的情景(比如说代码有bug)。
如果使用fused位置提供者,用setExpirationDuration()设置超时,这个方法接收的参数时以毫秒为单位的一个时间段,这个时间段从调用setExpirationDuration()开始计时;也可以用setExpirationTime()添加超时时间,这个方法接收一个毫秒计的时间,这个时间从系统启动开始计时。
对所有的非前台应用,把多请求捆绑处理。可以用setInterval()方法指定你想计算位置的频率。然后用setMaxWaitTime()方法设置位置信息提交的频率。setMaxWaitTime()的参数应该是setInterval()的几倍。例如,下面的例子:
LocationRequest request = new LocationRequest();
request.setInterval(10 * 60 * 1000);
request.setMaxWaitTime(60 * 60 * 1000);
这个例子中,每10分钟计算一次位置,每60分钟提交一次位置,每次提交包括六次位置信息。虽然你依然能得到每10分钟的位置信息,但是你的应用只会在一小时才启动一次。
用被动位置更新
在后台应用中,节约使用位置更新很重要。Android8.0的限制强制了这些,但是运行在老设备上的应用也应该尽量限制这些位置更新。
有可能你的应用在后台运行,而另一个前台应用正在频繁的请求位置更新。位置服务将这些更新的信息提供给你的应用。考虑下面的代码,它将适时地收到位置信息。
LocationRequest request = new LocationRequest();
request.setInterval(
15 * 60 * 1000);
request.setFastestInterval(
2 * 60 * 1000);
在前面的例子中,大约每15分钟进行一次位置计算。如果其它应用正在请求位置更新,那么位置信息最快以两分钟一次的频率传给你。
尽管被动接收位置信息不另外耗电,一定要小心,因为接收位置数据触发了CPU和I/O这些耗电的操作。为了降低耗电,setFastestInterval()里的间隔不应太小。
按照本文介绍的方法,你可以明显地提高电池性能。如果你的应用耗电小,用户倾向于不卸载你的应用。