@zongwu
2017-01-05T06:15:34.000000Z
字数 5665
阅读 401
技术交流
优先级作业队列是专门为Android编写的作业队列的实现,可轻松安排在后台运行的作业(任务),提高用户体验和应用程序稳定性。
它主要是考虑到灵活性和功能。这是一个正在进行的项目,我们将继续增加稳定性和性能改进。
项目地址:android-priority-jobqueue
几乎每个应用程序都在后台线程中工作。期望这些“后台任务”能够保持应用程序响应和鲁棒性,特别是在不利的情况下(例如遭限制的网络连接)。在Android应用程序中,有几种方法来实现后台工作:
最简单的方式是使用Async Task,但它与活动生命周期紧密耦合。如果活动死亡(或重新创建),任何正在进行的异步任务将成为浪费的周期或否则在返回到主线程时产生意外的行为。此外,仅仅因为用户旋转他/她的电话,就导致丢弃来自网络请求的响应是糟糕的做法。
Loaders
Loaders 是一个更好的选择,因为它们在配置更改后恢复。但另一方面,它们被设计为从磁盘加载数据,并且不适合长时间运行的网络请求。
Service with a Thread Pool
使用服务是一个更好的解决方案,因为它将业务逻辑与您的UI分离。但是,您将需要一个线程池(例如ThreadPoolExecutor)来并行处理请求,广播事件以更新UI,并编写额外的代码以将排队的请求保留到磁盘。随着应用程序的增长,后台操作的数量增加,这迫使您考虑任务优先级和常常复杂的并发问题。
作业队列为您提供了一个良好的框架来做所有上述和更多。您将后台任务定义为作业,并将其排入到JobManager。作业管理器将负责优先级,持久性,负载平衡,延迟,网络控制,分组等。它还为您的工作提供了良好的生命周期,以提供更好,一致的用户体验。
虽然不是必需的,但在与Event Bus一起使用时最有用。它还支持依赖注入。
作业队列的灵感来自关于REST客户端应用程序的Google I / O 2010演讲。
定义JOB
// 一个发送推文的作业
public class PostTweetJob extends Job {
public static final int PRIORITY = 1;
private String text;
public PostTweetJob(String text) {
// 此作业需要网络连接
// 并且应该在应用程序在作业完成之前退出的情况下持久保存。
super(new Params(PRIORITY).requireNetwork().persist());
}
@Override
public void onAdded() {
// 作业已保存到磁盘。
// 这是一个调度UI事件以指示作业最终将运行的好地方。
// 在这个例子中,最好用新发布的tweet更新UI。
}
@Override
public void onRun() throws Throwable {
// 作业逻辑在这里。在这个例子中,在这里完成到Twitter的网络调用。
// 这里做的所有工作应该是同步的, 当方法执行完毕后Job会从队列中移除。
webservice.postTweet(text);
}
@Override
protected RetryConstraint shouldReRunOnThrowable(Throwable throwable, int runCount,
int maxRunCount) {
// onRun中发生错误。
// 返回值确定此作业是否应重试或取消。
// 您可以进一步指定回退策略或更改作业的优先级。 您还可以将延迟应用于整个组,以保留作业的运行顺序。
return RetryConstraint.createExponentialBackoff(runCount, 1000);
}
@Override
protected void onCancel(@CancelReason int cancelReason, @Nullable Throwable throwable) {
// 作业已超过重试尝试次数,或者shouldReRunOnThrowable()已决定取消。
}
}
触发JOB
public void onSendClick() {
final String status = editText.getText().toString();
if(status.trim().length() > 0) {
jobManager.addJobInBackground(new PostTweetJob(status));
editText.setText("");
}
}
就这么简单,JobManager提供如下优点:
在Lollipop版本,Android引入了JobScheduler,这是一种系统友好的方式来运行non-time-critical
任务。它使你的代码更清洁,使你的应用程序是一个良好的公民的生态系统,它是通过GCMNetworkManager backported。
第一个作业队列版本是在Job Scheduler之前大约2年创建的。主要区别是作业队列设计为运行所有后台任务,而Job Scheduler仅设计用于可以延迟的任务。
使用作业队列的一个好办法是将所有网络任务写入作业,并使用AsyncTasks进行磁盘访问(例如从sqlite加载数据)。如果您有长时间运行的后台操作(例如处理图像),最好使用作业队列。
从v2开始,作业队列可以与JobScheduler或GCMNetworkManager集成。此集成允许作业队列根据作业的标准唤醒应用程序。你可以在相关的wiki页面看到详细描述。Scheduler API非常灵活,如果您的目标市场没有Google Play服务,您可以实现自定义版本。
在PostTweetJob与磁盘同步之后,作业队列调用DependencyInjector(如果提供),这将向我们的作业实例注入字段。在PostTweetJob.onAdded()回调中,我们将PostTweetJob保存到磁盘。由于到目前为止还没有网络访问,点击发送按钮和到达onAdded()之间的时间在几分之一秒内。这允许onAdded()的实现通知UI几乎立即显示新发送的推文。
在V1中,onAdded()被调用时线程作业被添加。
在V2中,onAdded()在JobManager自己的线程中被调用
当PostTweetJob运行时,作业队列将调用onRun()(只有在有工作的网络连接时才会被调用,正如在作业的构造函数中所指出的)。默认情况下,作业队列使用一个简单的连接实用程序检查ConnectivityManager(确保您在清单中具有ACCESS_NETWORK_STATE权限)。您可以提供可以添加其他检查(例如您的服务器稳定性)的自定义实现。您还应该提供一个NetworkUtil,它可以在网络恢复时通知作业队列,以便作业队列避免繁忙的环路并减少#个用户(默认配置适合您)。
我们通过maven中心仓库分发工件。
Gradle: compile 'com.birbit:android-priority-jobqueue:2.0.1'
我们强烈建议您检查如何配置作业管理器和单个作业。
- Configure job manager
- Configure individual jobs
- Review sample app
- Review sample configuration
如果队列已满,则固定高CPU使用率(#262)
处理作业调度程序的错误输入(#254)
验证JobManager ids
GCMNetworkManager中的小改进
修复了关于取消持久性作业的错误(#212)
修复了持久队列中的游标泄漏(#206)
向BatchingScheduler添加自定义持续时间(#202)
承诺最终2.0 API和向后兼容性
修正了一个错误,取消原因没有传递到onCancel如果Job决定不再试一次
重要修正与框架计划程序,它没有正确设置延迟
引入期限参数。作业将在其到达期限时运行(或取消),而不考虑其约束。
通过使基本作业完全瞬态,更容易编写自定义序列化程序。
将持久作业数据移动到单个文件,这将提高作业大小的限制。
如果作业序列化失败,JobManager将抛出异常。
新的onCancel API接收异常
更改了如何构建调度程序以避免NPE问题
新的ThreadPool配置允许为消费者创建自定义线程
有70多个提交的重大重写
迁移指南
默认NetworkUtil现在是Doze意识。 (感谢@coltin)
RetryConstraint延迟可应用于组以保留作业的执行顺序。 (#41)
修复了由主线程上的同步引起的潜在ANR。问题#40
固定的默认指数退避。问题#33
添加了在重试前更改作业优先级或添加延迟的功能。此机制可用于向作业添加指数退避。
添加了作业#getApplicationContext作为方便的方法来获取作业中的上下文。
修复了问题#19,如果该组中的作业在运行时被取消,然后onRun失败,该组永远阻止该组。
更新Robolectric版本,并将所有测试移动到Gradle。
再见Cobertura,欢迎Jacoco!
能够向作业添加标签。这些标记可用于以后检索作业。
增加了期待已久的工作取消。您可以使用标签取消作业。
删除已弃用的BaseJob类。这可能会破坏向后兼容性。
如果addInBackground失败,则报告异常到记录器。 (#31)
修复了一个重要的错误(#35),其中同一组中的作业可以并行运行,如果多个用户线程正在等待新作业,同时多个作业可用。
作业状态查询API(#18)
修复了网络状态长时间变化后的stackoverflow bug。 (#21)
为Job提供了更具可读性的参数化构造函数。
弃用BaseJob,有利于更完整的Job类。
首次公开发布。
Dependencies