我有一项任务是在Android应用中运行多个不同的工作。每个作业都是长期运行的,并且很多地使用网络,数据库和文件系统。每个作业都可以由用户手动运行或由AlarmManager调度。每个作业运行到最后都非常重要,因此需要在用户离开应用程序后继续运行,或者甚至在用户根本不打开应用程序时。乔布斯有一些ID属性:
class Job {
int id;
}
我需要这个假设的JobManager来接收作业并按ID排序。如果id = 1的作业已在运行,则JobManager应跳过id = 1的所有后续作业,直到此作业完成。但是如果提交的作业的id = 2,则它被接受并且可以与第一份作业并行运行。
作业也应该保持唤醒锁定直到完成,就像在CommonsWare的WakefulIntentService中完成一样。
我有几个想法如何实现这一点,但都有它们的缺点:
现有的图书馆已为此目的而设。至于现在除了CWAC-Wakeful我发现:
但我仍然不知道如何使用这些库来运行一个集中服务,它可以接受来自任何其他Activity,Service,BroadcastReceiver,AlarmManager等的作业,按ID排序并并行运行
请告诉我在这种情况下可以使用什么解决方案。
更新:请参阅下面我自己的解决方案。我不确定,它是否适用于所有可能的情况。如果您发现可能出现的任何问题,请发表评论。
答案 0 :(得分:2)
这似乎适用于Lollipop上的新JobScheduler API,然后你必须围绕它来实现包含sdk实现缺失的所有功能。
如果您需要在Lollipop以下的版本上实现此功能,那么有一个compat库。
答案 1 :(得分:1)
如果有人遇到同样的问题,这就是我提出的解决方案。我使用了Robospice lib,因为它是在服务上运行某些作业并将结果同步回Activity的最强大的方法。由于我没有找到任何方法将此lib与WakeLocks一起使用,我扩展了2个类:SpiceManager和SpiceRequest。新类WakefulSpiceManager和WakefulSpiceRequest实际上借用了CommonsWare关于WakeLocks的想法,实现非常相似。
WakefulSpiceManager:
public class WakefulSpiceManager extends SpiceManager {
private static final String NAME = "WakefulSpiceManager";
private static volatile PowerManager.WakeLock wakeLock;
private Context context;
public WakefulSpiceManager(Context context, Class<? extends SpiceService> spiceServiceClass) {
super(spiceServiceClass);
this.context = context;
start(context);
}
private static synchronized PowerManager.WakeLock getLock(Context context) {
if (wakeLock == null) {
PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NAME);
wakeLock.setReferenceCounted(true);
}
return wakeLock;
}
public <T> void execute(WakefulSpiceRequest<T> request, RequestListener<T> requestListener) {
PowerManager.WakeLock lock = getLock(context);
lock.acquire();
request.setLock(lock);
// explicitly avoid caching
super.execute(new CachedSpiceRequest<T>(request, null, ALWAYS_EXPIRED), requestListener);
}
}
WakefulSpiceRequest:
public abstract class WakefulSpiceRequest<R> extends SpiceRequest<R> {
private PowerManager.WakeLock lock;
public WakefulSpiceRequest(Class<R> clazz) {
super(clazz);
}
public void setLock(PowerManager.WakeLock lock) {
this.lock = lock;
}
@Override
public final R loadDataFromNetwork() throws Exception {
try {
return execute();
} finally {
if (lock.isHeld()) {
lock.release();
}
}
}
public abstract R execute() throws Exception;
}
所以基本上我们每次要从WakefulSpiceManager发送请求时都会获取锁。之后,锁被传递给WakefulSpiceRequest。当请求完成其工作时,它会使用release()方法清除锁定 - 即使已经销毁了WakefulSpiceManager的活动,也会发生这种情况。
现在我们以通常的Robospice的方式使用这些类,唯一的例外是我们只需要传递WakefulSpiceRequests以在WakefulSpiceManager上执行:
WakefulSpiceManager manager = new WakefulSpiceManager(context, MyService.class);
manager.execute(new WakefulSpiceRequest<MyResult>(MyResult.class) {
@Override
public MyResult execute() throws Exception {
return ...
}
}, new RequestListener<MyResult>() {
@Override
public void onRequestFailure(SpiceException e) {
...
}
@Override
public void onRequestSuccess(MyResult result) {
...
}
});
答案 2 :(得分:-1)
新Workmanager将帮助您按任意顺序安排任务。您可以轻松地为要添加的作业设置约束,同时还可以通过JobScheduler API或报警管理器设置许多其他优势。看一下这个视频的简短介绍 - https://www.youtube.com/watch?v=pErTyQpA390(WorkManager at 21:44)。
编辑:更新了我的ans以显示新API的功能 你不需要id来处理这个工作。您可以简单地将任务排入队列,其余的将由API本身处理。
一些工作案例场景
WorkManager.getInstance()
.beginWith(workA)
// Note: WorkManager.beginWith() returns a
// WorkContinuation object; the following calls are
// to WorkContinuation methods
.then(workB)
.then(workC)
.enqueue();
WorkManager.getInstance()
// First, run all the A tasks (in parallel):
.beginWith(workA1, workA2, workA3)
// ...when all A tasks are finished, run the single B task:
.then(workB)
// ...then run the C tasks (in any order):
.then(workC1, workC2)
.enqueue();