# android-jobqueue
**Repository Path**: alpha4/android-jobqueue
## Basic Information
- **Project Name**: android-jobqueue
- **Description**: No description available
- **Primary Language**: Android
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2016-07-28
- **Last Updated**: 2024-11-29
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
### V2 预备中
该版本的主要偏向于稳定性与新功能的修改。虽然目前还不是正式发布版本,但本人还是强烈推荐你使用2.0.
See the migration guide here: [从 v1 迁移到 v2](https://git.oschina.net/alpha4/android-jobqueue/wikis/V1-to-V2-migration)
``` gradle
dependencies {
compile 'com.birbit:android-jobqueue:2.0.0-beta2'
}
```
Android Priority Job Queue (Job Manager)
==========================
Job Manager 是为 Android 实现的[Job Queue](http://en.wikipedia.org/wiki/Job_queue)。为了在异步线程更容易的调度任务,改善用户体验和应用程序的稳定性。它是基于[flexibility][10]&[functionality][11]进行设计的。
这是一个持续维护的项目,我们会持续增加稳定性与提升性能。
- [为什么需要 Job Manager ?](#why-)
- [我们遇到的问题](#the-problem)
- [我们的解决方案](#our-solution)
- [阅读源代码](#show-me-the-code)
- [Priority Job Queue vs Job Scheduler vs GCMNetworkManager vs ?](#priority-job-queue-vs-job-scheduler-vs-gcmnetworkmanager-vs-)
- [实现原理?](#under-the-hood)
- [优势](#advantages)
- [接入指南](#getting-started)
- [历史迭代版本](#version-history)
- [执行测试用例](#running-tests)
- [文档说明][9]
- [外部依赖](#dependencies)
- [版权声明](#license)
### Why ?
#### The Problem
绝大部分的应用程序在背景线程中执行耗时操作。
这些“背景任务”期望得到响应并且具有好的健壮性,尤其是在面临异常状况时(比如网络连接)。
在 Android 应用中,有以下几种方式可以实现耗时操作:
* **Async Task:** 最简单的方式莫过于使用 `AsyncTask`, 但不幸的是它与生命周期紧密的耦合. 如果 `Activity`被销毁或重建, 此时仍在运行中的任务将面临两种情况,周期性的浪费或者异常的回调到主线程。 此外, 另一个让人受不了的场景是当用户旋转他的手机之后,就会丢失原先发出的请求。
* **Loaders:** `Loaders`相对来说是个不错的选择, 因为当配置变更后他们也会同步变更. 另一方面,他们被设计用来从 disk 中加载数据,所以并不是很适用于长时间耗时的网络操作。
* **Service with a Thread Pool:** 使用`Service`较`Loader`会更好, 因为他讲业务请求与 UI 解耦.但是,你需要使用线程池(如:`ThreadPoolExecutor`)并发的去执行这些请求、将请求结果广播给 UI、并将请求持久化到 disk。随着应用规模的不断增长,你将会考虑任务的优先级及遇到各种难以理解的并发问题。
#### Our Solution
Job Queue 提供了优秀的框架以支持上述及更多的需求. 你讲耗时操作定义为 [Jobs][11] 并将它们入队到你的[JobManager][10] 实例中.
Job Manager 会关注以下方面:
- 优先队列
- 持久化
- 负载均衡
- 延迟执行
- 网络控制,
- 分组
- ...
同样的它也为你的任务提供了一个好的生命周期,这有利于提高用户体验。虽然不是必须, 结合`EventBus`使用上手体验更好. 它也提供了DI功能。
* Job Queue 的灵感来源于[Google I/O 2010 talk on REST client applications][8].
### Show me the code
一行代码胜过千言万语,请看代码
文件: [PostTweetJob.java](https://git.oschina.net/alpha4/android-jobqueue/blob/master/examples/twitter/TwitterClient/src/com/birbit/android/jobqueue/examples/twitter/jobs/PostTweetJob.java)
``` java
// 发送一条 tweet 消息的 job
public class PostTweetJob extends Job {
public static final int PRIORITY = 1;
private String text;
public PostTweetJob(String text) {
// 需要依赖网络连通 -- requireNetwork
// 并且除非应用程序关闭其他请看下都需要确保该任务完成。 -- persist
super(new Params(PRIORITY).requireNetwork().persist());
}
@Override
public void onAdded() {
// 任务已经被保存到 disk 上。
// 可以在此处告诉 UI,这个任务最终会被运行。
// 在当前的例子下,可以告诉用户这个任务准备执行了。
}
@Override
public void onRun() throws Throwable {
// 任务的主体业务逻辑.
// 此例中,发送给Twitter的网络请求将在此处完成。
// 所有在此处完成的任务都将是异步的,将onRun()执行完毕后。该任务将从 queue 中移除。
webservice.postTweet(text);
}
@Override
protected RetryConstraint shouldReRunOnThrowable(Throwable throwable, int runCount,
int maxRunCount) {
// onRun()执行失败,shouldReRunOnThrowable()的返回值来决定任务是否需要重试或取消。
// 你可以在此处定义补偿策略或者调整该任务的优先级。
// 也可以Delay 这个任务所在的分组,以保证按照顺序执行。
return RetryConstraint.createExponentialBackoff(runCount, 1000);
}
@Override
protected void onCancel(@CancelReason int cancelReason, @Nullable Throwable throwable) {
// 任务超过重试次数 或者 shouldReRunOnThrowable()方法返回策略为取消。
}
}
```
文件: [TweetActivity.java](https://git.oschina.net/alpha4/android-jobqueue/blob/master/examples/twitter/TwitterClient/src/com/birbit/android/jobqueue/examples/twitter/SampleTwitterClient.java#L53)
``` java
//...
public void onSendClick() {
final String status = editText.getText().toString();
if(status.trim().length() > 0) {
jobManager.addJobInBackground(new PostTweetJob(status));
editText.setText("");
}
}
...
```
Job Manager 提供你如下享受:
* 没有需要依赖于 Activity 生命周期的网络调用
* 没有乱七八糟的序列化请求
* 不用手动配置网络状态检查或重试逻辑
### Priority Job Queue vs Job Scheduler vs GCMNetworkManager vs ?
在 Lollipop 版本中, Android 首次引入 [JobScheduler][14] ,这是一种由系统提供的好友方式去执行非时间相关的任务。
它将使你的代码变得更整洁,使用你的 app 更好遵循 Android 生态系统。Job Scheduler 是[GCMNetworkManager][15]的补丁。
Job Queue 的首个版本比 Job Scheduler 早了大约2年。他们两者间最大的区别在于,Job Queue允许你执行**所有**的任务而Job Queue只支持那么**可被延迟**的那些。
我们创建 Job Queue 的原因是想尽可能的剥离那些不需要再主线程执行的逻辑块。我们需要一个便捷的方式去区分优先级,即便重启也能恢复、及分组权限控制。
我们推荐的实践是使用 Job Queue 去编写**所有**的网络任务,使用**AsyncTasks**编写读取磁盘等操作。
假如你有其他的耗时操作,如:“处理一张图片”,使用 Job Queue 去处理也是一个不错的选择。
从 **v2**开始, Job Queue 整合了 JobScheduler 或 GCMNetworkManager。 这种整合允许 Job Queue 基于标准的队列去唤醒。 你可以在 [wiki][16] 上找到关联的所有细节.
`Scheduler API `也是灵活的,这意味着你可以在不支持 Google Service的设备实现自定义的一套调度逻辑。
### Under the hood
* 当用户点击发送按钮时, `onSendClick()` 被调用时创建了 `PostTweetJob`实例并将它添加到 JobQueue 中以待执行。Job 将在背景线程中执行,因此 JobQueue 将对应的 Job 持久化到本地。
* 在 `PostTweetJob` 正确同步到磁盘后, Job Queue 调用 `DependencyInjector` (如有) 将会注入 [inject fields](http://en.wikipedia.org/wiki/Dependency_injection) 注入到我们的 JobQueue 实例中。
在 `PostTweetJob.onAdded()` 回调中, 我们将 `PostTweetJob` 实例保存到磁盘中。 在此过程之中无需网络访问, 点击发送按钮到响应方法 `onAdded()` 通常只需要几分之一秒。
这允许在方法 `onAdded()` 中通知 UI 显示最新的发送消息操作立即准备执行, 给用户一个快速的操作体验。
在 V1, `onAdded()` 在 Job 被线程添加的时候调用。
在 V2, `onAdded()` 在 JobManager 自己的线程中调用。
* 当 `PostTweetJob` 真正执行时, Job Queue 将会调用方法 `onRun()` (正如它构造器中描述的那样,它只会在网络环境生效的情况下才会被调用)。
默认, Job Queue 使用简单的网络连接工具类 `ConnectivityManager` 检查网络状态(确保你在配置文件中注册了权限 `ACCESS_NETWORK_STATE` )。
你也可以提供一个 [自定义的实现][1] 以添加更多的功能 (比如:检测服务器稳定性)。 你也应该提供 [`NetworkUtil`][1] 这样当网络可用时通知 Job Queue 及时恢复,以减少无用的循环等待。
* Job Queue 会一直调用 `onRun()` 直到返回成功 (或达到失败重试次数)。如果 `onRun()` 抛出异常,Job Queue 会调用 `shouldReRunOnThrowable()` 允许你捕获异常并决定是否要继续重试或者取消任务。
* 如果所有的重试都返回失败(或方法 `shouldReRunOnThrowable()` 返回为 false), Job Queue 会调用方法 `onCancel()` 允许你去做一些事件(如:清理数据库,通知用户等)。
### Advantages
* 它很容易的将应用程序的业务逻辑从`Activity`中解耦出来,使你的代码具有更好的健壮性、易于重构、**测试**。
* 你不用解决 `AsyncTask` 的生命周期问题,假设你使用`EventBus`去通知UI 刷新(我们也建议结合 EventBus)。
在 Path 应用中, 我们使用[greenrobot's EventBus](https://github.com/greenrobot/EventBus); 当然,你也可以选择那些你喜欢的 (比如: [Square's Otto] (https://github.com/square/otto))
* Job Queue 谨慎的处理有序 Job,检查网络连接状态,并发的执行等。 Job 优先级是格外不能缺少的东西尤其是当你的 app 是很重资源的应用。
* 你可以延迟处理任务。比如:将 GCM Token 注册到你的服务器。 是很常见的获取GCM Token并将其发送到服务器。尤其是当用户登录到你的应用程序,但你不想让它干扰关键网络操作(如获取面向用户的内容)。
* 你可以将 Job 归类到组,以确保他们是串行执行。 举例来说, 你是一个消息客户端,当你创建好多个 `SendMessageToNetwork` 任务,还没来得及执行时网络挂掉了,此时你可以以 conversation ID 作为分组的标识。 通过这种方式,同一个会话里的消息(Job 已入队)的发送顺序得以保存,如果是多个会话则会并发的执行。这使您可以轻松地最大化网络利用率,确保数据的完整性。
* 默认, Job Queue 监视网络连接状态 (因此你可以不用担心)。 当设备离线时,队列中的 Jobs 将会停止除非网络再次得到恢复。 甚至你可以提供自定义的 [`NetworkUtil`][1] 如果你需要重新定义网络恢复的逻辑。 (比如:你只希望在WIFI 状态下才会自动的恢复队列中的Jobs)。
* 它拥有良好的单元测试和丰富的文档注释。 你可以检查 [代码覆盖率报告][3] 与 [Javadoc][4]。
### Getting Started
我们使用 Maven 管理中间件:
Gradle: `compile 'com.birbit:android-jobqueue:2.0.0-beta2'`
Maven:
``` xml
The MIT License (MIT) Copyright (c) 2013 Path, Inc. Copyright (c) 2014 Google, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.[1]: https://git.oschina.net/alpha4/android-jobqueue/blob/master/jobqueue/src/main/java/com/birbit/android/jobqueue/network/NetworkUtil.java [2]: https://git.oschina.net/alpha4/android-jobqueue/blob/master/jobqueue/src/main/java/com/birbit/android/jobqueue/network/NetworkEventProvider.java [3]: http://yigit.github.io/android-jobqueue/coverage-report/index.html [4]: http://yigit.github.io/android-jobqueue/javadoc/index.html [5]: http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22android-jobqueue%22 [6]: https://git.oschina.net/alpha4/android-jobqueue/tree/master/examples [7]: https://git.oschina.net/alpha4/android-jobqueue/blob/master/examples/twitter/TwitterClient/src/com/birbit/android/jobqueue/examples/twitter/TwitterApplication.java#L26 [8]: http://www.youtube.com/watch?v=xHXn3Kg2IQE [9]: https://git.oschina.net/alpha4/android-jobqueue/wiki [10]: https://git.oschina.net/alpha4/android-jobqueue/wikis/Job-Manager-Configuration [11]: https://git.oschina.net/alpha4/android-jobqueue/wikis/Job-Configuration [12]: https://git.oschina.net/alpha4/android-jobqueue/blob/master/jobqueue/src/main/java/com/birbit/android/jobqueue/Params.java [13]: https://git.oschina.net/alpha4/android-jobqueue/wikis/V1-to-V2-migration [14]: https://developer.android.com/reference/android/app/job/JobScheduler.html [15]: https://developers.google.com/android/reference/com/google/android/gms/gcm/GcmNetworkManager [16]: https://git.oschina.net/alpha4/android-jobqueue/wikis/Integration-with-JobScheduler-and-GcmNetworkManager