用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 网络管理器和如何使用来保护电源,好了,就到这里吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值