用android的GCM 网络管理来优化电池使用时间
Posted 扈扈哈嘿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用android的GCM 网络管理来优化电池使用时间相关的知识,希望对你有一定的参考价值。
GCM网络管理器能让app注册能执行面向网络的服务,每个任务只是完成一个工作。它的API能处理这些任务,允许Google Play Services通过系统集中处理这些网络操作。
它的API有助于简化通用的网络模式,比如说等待网络连接,网络重联和回退等。实事上,GCM网络管理器通过直观的API允许开发者更加有精力关注具体的功能实现,少一点精力去关心网络的问题。
电池使用与网络访问的关系
在介绍GCM网络管理器之前,我们花点精力来认识一下电池与网络请求的利害关系,这样我们才能明白为什么批处理网络这么重要。
这里有张android无线电状态机的图表
这已经很直观了,我用这张图表来加固对处理网络连接的时候唤醒radio是一个巨大消耗的过程的这个概念。本身嘛,调用网络就是一个对电量的有巨大消耗的操作。
即使没有单一的网络任务可以消耗完电量,但是大量的个别的可以唤醒radio的网络请求就可以。如果网络请求彼此分开,然后设备伴随着radio的打开被唤醒,因为电池的消耗被唤醒的设备不能休眠(就像睡不戳的人一样)。
下面的这图表展示网络请求来处一个获取图片的app,这个app叫PhotoGallery
好吧,单个请求看起来不是太坏,radio是打开了,但也只是一个请求,是吧?
下面这张图显示的多个网络调用:
突然我们有了大量的网络请求,radio会被每个请求快速唤醒,这样会很消耗掉电量,而导致极其不好的用户体验。
我们可以批处理网络请求来节约电量,主要是优化唤醒radio的消耗。如果在radio的生命同期中最消耗的是初始化唤醒阶段,那么我们就只需要通过批处理来只唤醒一次就好了。这个方法适合不立即需要数据的情况,预加载吧。
下面这个图表就是反批处理网络请求的:
现在这个radio就只被唤醒一次,节约了电量。
但是有的时候你确实马上就需要网络请求,比如你正在打游戏或者发送一个消息。对于这些情况来说,你应该做一个普通的网络请求,但是,请注意这种类型的网络请求并不能优化电量。
GcmTaskService
既然我们已经看到了用批处理网络来有效的优化电量的实用性,那现在就让我们来探索GCM网络管理在app中的使用。
dependencies
compile 'com.google.android.gms:play-services-gcm:8.1.0'
确定仅仅依赖Google Play Services 的GCM的子集,否则你将会引进许多不必要的方法到你的app中。
接下来。我们必需在AndroidManifest中声明一个新的Service。
<service android:name=".CustomService"
android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
</intent-filter>
</service>
CustomSerice是一个继承自GcmTaskService的类,它是处理GCM网络管理器的核心类。这个Sergice处理任务,这些任务是我们想要完成的任务,用 action SERVICE_ACTION_EXECUTE_TASK 来接收GCM网络管理器的准备执行的通知。
接下来,我们创建一个CustomService.java的类来继承GcmTaskService:
public class CustomService extends GcmTaskService
...
这个类只要运行可以随时执行任务,因为我们实现GcmTaskService ,我们必需在CustomService中实现OnRunTask方法:
@Override
public int onRunTask(TaskParams taskParams)
Log.i(TAG, "onRunTask");
switch (taskParams.getTag())
case TAG_TASK_ONEOFF_LOG:
Log.i(TAG, TAG_TASK_ONEOFF_LOG);
// This is where useful work would go
return GcmNetworkManager.RESULT_SUCCESS;
case TAG_TASK_PERIODIC_LOG:
Log.i(TAG, TAG_TASK_PERIODIC_LOG);
// This is where useful work would go
return GcmNetworkManager.RESULT_SUCCESS;
default:
return GcmNetworkManager.RESULT_FAILURE;
我们检查给的参数来对比TaskParams的tag 来执行相应的代码,在对应的分支里面我们可以做复杂的逻辑操作,在demo里面只是用Log打印了些信息。
GcmNetworkManager
即使我们初始化了GcmTaskService,我们也必需要拿到GcmNetworkManager的引用对象,这个引用会作为刚刚Services执行任务时的hook。
private GcmNetworkManager mGcmNetworkManager;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
mGcmNetworkManager = GcmNetworkManager.getInstance(this);
这个GcmNetworkManager对象将被用来执行任务,其中一个方法就是在onCreate中初始化这个成员变量,还有就是当你需要GcmNetworkManager的实例来执行任务时再获取实例。
Scheduling Tasks
一个单一任务是执行一个任务,这里有两种类型:一次性的和定期的。
我们通过任务窗口提供一个任务,然后调度器决定实际执行时间,因为任务并不是需要立即执行的,所以调度器会几个网络请求作为批处理来节约电量。
调度器会考虑到网络的可用性,网络活动和网络加载。如果都没有这些问题,调度器通常会处于等待状态直到指定窗口的结束。
下面是我怎么样执行一次性任务:
Task task = new OneoffTask.Builder()
.setService(CustomService.class)
.setExecutionWindow(0, 30)
.setTag(LogService.TAG_TASK_ONEOFF_LOG)
.setUpdateCurrent(false)
.setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
.setRequiresCharging(false)
.build();
mGcmNetworkManager.schedule(task);
这里用的是Builder 模式,我们定义所有的参数在我们的任务中:
1. Service 可以控制任务的明确的GcmTaskService,允许我们可以取消
2. Execution window 任务执行的时间段,第一个是下边界,第二个是上边界,单位都是s,这个是强制的
3. Tag 用来标记onRunTask 方法中哪个任务是当前执行的。每个tag都应该是唯一的,最大的长度是100.
4. Update Current 这个决定是否应该替换前面一个拥有同一个tag的任务,默认是false,所以新的任务不会覆盖已经存在的任务
5. Required Network 设置一个指定的网络状态支运行,如果网络状态是不可用,那么一直等到网络可用再执行。
6. Requires Charging 是否应该在设备连接电源的情况下执行任务。
全部都设置完成,由GcmNetworkManager的实例来执行。
定时任务如下 :
Task task = new PeriodicTask.Builder()
.setService(CustomService.class)
.setPeriod(30)
.setFlex(10)
.setTag(LogService.TAG_TASK_PERIODIC_LOG)
.setPersisted(true)
.build();
mGcmNetworkManager.schedule(task);
看起来很像,但是有几次不一样
1. Period 指定任务最多每间隔多长时间执行一次,单位是s,默认地,我们不能控制在这个时间段具体哪个时间执行,这个设置是强制要设置的。
2. Flex 指定在靠近结束时间(上个参数设置)内执行任务,如果时间段是30s,flex是10,调度器会在20-30之间执行。
3. Persisted 决定任务是不是应该在重启之后继续存在,默认是true,这个对一次性任务不支持,要求获得”Receive Boot Completed”权限,否则这个设置会被忽略。
我们看到了使用GCM网络管理器api的强大,调度器创建的即简单又灵活。
看起来很像,但是有几次不一样
Period 指定任务最多每间隔多长时间执行一次,单位是s,默认地,我们不能控制在这个时间段具体哪个时间执行,这个设置是强制要设置的。
Flex 指定在靠近结束时间(上个参数设置)内执行任务,如果时间段是30s,flex是10,调度器会在20-30之间执行。
Persisted 决定任务是不是应该在重启之后继续存在,默认是true,这个对一次性任务不支持,要求获得”Receive Boot Completed”
权限,否则这个设置会被忽略。
我们看到了使用GCM网络管理器api的强大,调度器创建的即简单又灵活。
取消任务
我们知道了怎么执行任务,所以我们现在来看看怎么取消任务,我们不取消正在执行的任务,不过我们可以取消还没有执行的任务。
我们可以用给定的GcmTaskService来取消所有的任务:
mGcmNetworkManager.cancelAllTasks(CustomService.class);
我们也可以取消特定tag的任务:
mGcmNetworkManager.cancelTask(
CustomService.TAG_TASK_PERIODIC_LOG,
CustomService.class
);
还有一种情况,记住我们不能取消飞行中的任务。
Google Play Services
我们需要Google Play Services 才能在调度方法中用GCM网络管理器来处理任务,为了安全的使用Google Play Services,我们需要检查它是否存在。如下所示:
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode == ConnectionResult.SUCCESS)
mGcmNetworkManager.schedule(task);
else
// Deal with this networking task some other way
如果没有Google Play Services,GcmNetworkManager将会静默失败,所以你需要检查。
同样的,当Google Play Services 或者app更新了,所有的执行任务都会被移除,为了避免失去你当前的执行任务, GcmNetworkManager将会调用我们GcmTaskService(也就是CustomService)的onInitializeTasks()方法,这个方法可以重新调度所有的任务,这个通常用来执行定时任务:
@Override
public void onInitializeTasks()
super.onInitializeTasks();
// Reschedule removed tasks here
简单地重写了这个方法,在里面重新执行必要的任务。
总结
我们一起深入了解了GCM 网络管理器和如何使用来保护电源,好了,就到这里吧。
以上是关于用android的GCM 网络管理来优化电池使用时间的主要内容,如果未能解决你的问题,请参考以下文章
Android 下的 Websockets 与 GCM:电池使用情况?
为啥 C2DM/GCM 不使用 SMS 作为传输来节省电池寿命?