Evernote带来的计划任务神器Android-Job

1533 字
8 分钟
Evernote带来的计划任务神器Android-Job

在新版本安卓版本(API23以上)中,谷歌把android.net.conn.CONNECTIVITY_CHANGE 这个广播废弃了。总的来说,应用不应该依赖这个广播来执行相关任务,而应该使用 JobScheduler 或者 GCMNetworkManager。计划任务的执行方案还可以用 AlarmManager。 对于国内的开发者来说,这是一个悲剧。Android 现在提供这三种不同的API来执行计划任务.这三种API都有各自的优缺点 。 android.net.conn.CONNECTIVITY_CHANGE 在高版本的系统中不可用了,JobScheduler 在低版本的系统中又不可用, GCMNetworkManager 是什么?在国内不存在。而且这些API之间的不同语义和用法对开发者是一种额外的负担。这种负担体现在我们不仅仅要懂得什么时候使用合适的API,而且要为不同的环境执行同样任务提供不同分支的代码。APP需要在运行时候用合适的条件判断到底要使用哪种方式执行计划任务。幸运的是,开源的世界有伟大的公司为我们提供了灵活的轮子。

Evernote 开源的 Android-Job 为我们带来兼容这三种API的方案,高效,简单,灵活。Android-Job 在运行判断使用哪种API,它提供 AlarmManager, JobSchedulerGcmNetworkManager功能的超集,比如说,我们可以定义计划任务在网络连通且在充电时候执行。

为兼容而生#

上面提到的三种方案,兼容维护非常麻烦。为了彰显Android-Job的价值,我们有必要对这三种方案做一个分析。

AlarmManager#

AlarmManager 的API一直在改变 ,所以我们需要非常注意我们APP目标运行系统是哪个版本。

** 优点 **

  • 所有设备上可用
  • 发送广播来启动一个服务执行计划很容易

** 缺点 **

  • API在不同系统版本表现不一致
  • 太多样板代码
  • 忽略了设备的状态
    alarmManager
    alarmManager

JobScheduler#

JobScheduler 只在Lollipop以上版本可用。

** 优点 **

  • 流式API简洁易用
  • 检查设备状态

** 缺点 **

  • 只在API 21+ 可用 (有些功能要求API24+)
  • 平台bug
  • 也是太多样板代码

GcmNetworkManager#

GcmNetworkManager 只有在安装有Google Play的设备上可用,而且,没有被墙。

** 优点 **

  • JobScheduler相似的API
  • 要求minSdkVersion 9

** 缺点 **

  • 是 GooglePlay ServicesSDK 的一部分
  • 不能脱离 Play Services 运行
  • API 有很多陷阱

例子#

Android-Job项目作者在一篇PPT中详细的说明了这三种方案以及Android-Job的用法。由于篇幅有限且排版原因,强烈建议点击链接去看看。例子简单易懂,在这里给出PPT对应的PDF文件。还在犹豫是否要使用 Android-Job ,看了这个PDF,相信你心里就有肯定的答案了 PDF传送门

使用Android-Job(翻译自项目说明)#

请保证点击以下链接检查你使用的是否是最新版本Android-Job最新版链接 添加以下的Gradle配置到安卓项目:

// 在app 项目的 build.gradle 文件:
dependencies {
compile 'com.evernote:android-job:1.1.7'
}

如果没有在 Gradle build tools 中关闭 manifest merger,那就不用更多步骤来配置这个工具库了。否则需要手动添加权限生命和services,参考这个AndroidManifest

用法#

JobManager 类作为入口。我们自定义的Jobs 需要继承 Job 类。使用对应的Builder类创建一个 JobRequest 然后使用 JobManager 创建这个计划请求。

使用 JobManager 之前必须向初始化这个单例。我们需要提供一个 Context 然后添加一个 JobCreator 实现类. JobCreator 把一个job tag 映射到一个特定的job 类。推荐在 ApplicationonCreate() 方法中 初始化 JobManager 。如果没有 Application 类的访问权限,这是可选的方案

public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
JobManager.create(this).addJobCreator(new DemoJobCreator());
}
}
public class DemoJobCreator implements JobCreator {
@Override
public Job create(String tag) {
switch (tag) {
case DemoSyncJob.TAG:
return new DemoSyncJob();
default:
return null;
}
}
}

然后我们可以开始计划要执行的任务。

public class DemoSyncJob extends Job {
public static final String TAG = "job_demo_tag";
@Override
@NonNull
protected Result onRunJob(Params params) {
// run your job here
return Result.SUCCESS;
}
public static void scheduleJob() {
new JobRequest.Builder(DemoSyncJob.TAG)
.setExecutionWindow(30_000L, 40_000L)
.build()
.schedule();
}
}

进阶用法#

JobRequest.Builder 类有很多额外的配置选项,例如,我们可以声明条件:需要网络连接。为了使任务周期性执行,用 bundle 传递额外的参数,使得任务在重启后或在特定的时间恢复。 每一个Job 有一个唯一的 ID 。这个 ID 帮助我们辨别 job ,以便将来更新条件或者取消 job。

private void scheduleAdvancedJob() {
PersistableBundleCompat extras = new PersistableBundleCompat();
extras.putString("key", "Hello world");
int jobId = new JobRequest.Builder(DemoSyncJob.TAG)
.setExecutionWindow(30_000L, 40_000L)
.setBackoffCriteria(5_000L, JobRequest.BackoffPolicy.EXPONENTIAL)
.setRequiresCharging(true)
.setRequiresDeviceIdle(false)
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
.setExtras(extras)
.setRequirementsEnforced(true)
.setPersisted(true)
.setUpdateCurrent(true)
.build()
.schedule();
}
private void schedulePeriodicJob() {
int jobId = new JobRequest.Builder(DemoSyncJob.TAG)
.setPeriodic(TimeUnit.MINUTES.toMillis(15), TimeUnit.MINUTES.toMillis(5))
.setPersisted(true)
.build()
.schedule();
}
private void scheduleExactJob() {
int jobId = new JobRequest.Builder(DemoSyncJob.class)
.setExact(20_000L)
.setPersisted(true)
.build()
.schedule();
}
private void cancelJob(int jobId) {
JobManager.instance().cancel(jobId);
}

如果非周期性的 Job 执行失败,我们可以设定恢复标准重新计划这个 job

public class RescheduleDemoJob extends Job {
@Override
@NonNull
protected Result onRunJob(Params params) {
// 一些异常情况发生,稍后重试这个Job
return Result.RESCHEDULE;
}
@Override
protected void onReschedule(int newJobId) {
// 恢复的Job有一个新的 ID
}
}

提醒: 谷歌在安卓 Marshmallow 版本引入自动备份功能,所有的 job 信息保存在一个文件名为 evernote_jobs.xml的 shared preference , 以及文件名为evernote_jobs.db 的数据库中. 我们应该排除这些文件,避免他们被自动备份。 我们可以定义一个resource XML 文件 (比如, res/xml/backup_config.xml) 内容如下:

<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<exclude domain="sharedpref" path="evernote_jobs.xml" />
<exclude domain="database" path="evernote_jobs.db" />
</full-backup-content>

然后在应用的 AndroidManifest.xml指向这个文件:

<application ... android:fullBackupContent="@xml/backup_config">

代码混淆#

这个库没有使用反射,但是它依赖两个 Service 以及两个 BroadcastReceiver 为了避免任何可能出现的问题,不应该混淆这四个类。这个库打包了它自己的混淆配置,所以我们不需要做任何额外的配置。以防万一,也可以在我们项目的混淆配置中添加这些规则

FAQ#

点击这里查看更多的疑问解答。

参考资料#

evernote的Blog 作者Ralf的PPT

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或打赏支持!

打赏
Evernote带来的计划任务神器Android-Job
https://ernest-su.github.io/android-job-from-evernote/
作者
Ernest
发布于
2017-03-23
许可协议
CC BY-NC-SA 4.0
相关文章智能推荐
1
GitHub上star超过2k的安卓MVP架构指南
架构近日在搜MVP模式作为安卓项目架构时候,发现GitHub上一篇介绍MVP架构的文章。一看star已经超过2K了。通读全文发现作者用实际项目将MVP架构要怎么分职责讲得十分通俗易懂。为了方便大家查阅,把原文翻译了一下。作者还有一篇文章讲安卓项目和代码风格指南的。欢迎查看相关翻译。
2
GitHub上star超过2k的安卓项目和代码风格指南(绝对干货)
最佳实践近日在搜MVP模式作为安卓项目架构时候,发现GitHub上一篇介绍MVP架构的文章。一看star已经超过2K了。作者同项目的这篇文章讲安卓项目和代码风格指南,也非常有参考价值。为了方便大家查阅,把原文翻译了一下。点击查看作者介绍安卓MVP架构指南的翻译文章。
3
Linux 命令手册安卓版
工具前两天逛GitHub时候发现了一个命令行手册项目jaywcjlove/linuxcommand 手册网站,觉得非常实用。GitHub的Pages很方便,但是国内访问有时候比较慢。虽然网上类似的在线手册很多了,但是我觉得一个手册应该是随手可用,而且即使在没有网时候,也可随时翻阅的。
4
Android处理dicom文件记录
Android纯java编写,网上有搜到android版本的jar包,是dcm4che低版本,只在安卓平台上实现了reader,没实现writer。github上的版本有reader和writer实现,但是是依赖javax相关包的,安卓上没有这些包。所以用不了github上的版本。
5
安卓开发相关框架文章收集(长期更新)
开发效率在做项目初期,如果知道有哪些框架/工具可用,对项目的开发会有很大的帮助。这篇帖子收集项目开发用过的,或者有类似需求不知道有对应工具,后来发现这些工具有相见恨晚感觉的。作为一个类似于备忘录的帖子,根据个人判断在需要的时候进行增删改查。介绍时候尽量用一两个关键词。收集的文章可能会因各
随机文章随机推荐
Profile Image of the Author
Ernest
一个有理想的Android程序员
公告
欢迎来到我的博客!这是一则示例公告。
音乐
封面

音乐

暂未播放

0:000:00
暂无歌词
分类
标签
站点统计
文章
27
分类
12
标签
47
总字数
123,546
运行时长
0
最后活动
0 天前
站点信息
构建平台
GitHub Actions
博客版本
Firefly v6.13.6
文章许可
CC BY-NC-SA 4.0

文章目录