我正在使用AndroidX Work Dependency尝试运行一些后台服务操作。发布此问题时,我当前正在运行最新的稳定版本2.2.0
。
我在后台运行的实际操作是一个相当繁重的CPU操作,因为它在我的一个库(here)中使用了一些压缩代码,并且可能需要3到30分钟的时间,具体取决于大小和长度有问题的视频。
这是我构建并运行工作请求的代码:
public static void startService(){
//Create the Work Request
String uniqueTag = "Tag_" + new Date().getTime() + "_ChainVids";
OneTimeWorkRequest.Builder builder = new OneTimeWorkRequest.Builder(CompleteVideoBackgroundService.class);
Constraints.Builder constraints = new Constraints.Builder();
constraints.setRequiredNetworkType(NetworkType.CONNECTED);
builder.setConstraints(constraints.build());
builder.setInitialDelay(1, TimeUnit.MILLISECONDS);
builder.addTag(uniqueTag);
Data inputData = new Data.Builder().putString("some_key", mySerializedJSONString).build();
builder.setInputData(inputData);
OneTimeWorkRequest compressRequest = builder.build();
//Set the Work Request to run
WorkManager.getInstance(MyApplication.getContext())
.beginWith(compressRequest)
.enqueue();
}
然后它会触发运行所有后台服务操作的此类:
public class MyServiceSampleForStackoverflow extends Worker {
private Context context;
private WorkerParameters params;
public MyServiceSampleForStackoverflow(@NonNull Context context, @NonNull WorkerParameters params){
super(context, params);
this.context = context;
this.params = params;
}
/**
* Trimming this code down considerably, but the gist is still here
*/
@NonNull
@Override
public Result doWork() {
try {
//Using using a hard-coded 50% for this SO sample
float percentToBringDownTo = 0.5F;
Uri videoUriToCompress = MyCustomCode.getVideoUriToCompress();
VideoConversionProgressListener listener = (progressPercentage, estimatedNumberOfMillisecondsLeft) -> {
float percentComplete = (100 * progressPercentage);
//Using this value to update the Notification Bar as well as printing in the logcat. Erroneous code removed
};
String newFilePath = MyCustomCode.generateNewFilePath();
//The line below this is the one that takes a while as it is running a long operation
String compressedFilePath = SiliCompressor.with(MyApplication.getContext()).compressVideo(
listener, videoUriToCompress.getPath(), newFilePath, percentToBringDownTo);
//Do stuff here with the compressedFilePath as it is now done
return Result.success();
} catch (Exception e){
e.printStackTrace();
return Result.failure();
}
}
}
[偶尔,没有任何韵律或理由,工人会随机停下,而我并没有要求这样做。发生这种情况时,我看到此错误:
Work [ id=254ae962-114e-4088-86ec-93a3484f948d, tags={ Tag_1571246190190_ChainVids, myapp.packagename.services.MyServiceSampleForStackoverflow } ] was cancelled
java.util.concurrent.CancellationException: Task was cancelled.
at androidx.work.impl.utils.futures.AbstractFuture.cancellationExceptionWithCause(AbstractFuture.java:1184)
at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:514)
at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:284)
at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
从字面上看,我只是盯着我的手机,而当这种随机情况发生时,它根本不与之互动。我不是在尝试运行其他应用程序,也不是在试图占用CPU其他资源。我从来没有看到自己的堆栈跟踪信息,也没有看到直接的问题或原因。
因此,问题是,在这里发生了什么事,它在没有任何挑衅的情况下随机停止了Worker服务? 为什么会随机停止操作?
谢谢。
编辑1
我确实测试过删除可能导致问题的网络约束要求行的想法,并且确实在此之后发生了,所以我不认为这是问题所在。
我正在Google Pixel 3,API 28,Android 9上进行测试,但是我测试过的任何其他设备(无论API级别如何(最低支持为21)都显示了相同的问题。
编辑2
ListenableWorker
而不是Worker
来重写该类以使用异步方法,但这无法解决问题。 您最有可能面临2个问题之一。
首先,假设您的后台服务运行超过[[10分钟can take anywhere from 3-30 minutes depending on the size and length of the video in question
,您可能会遇到由WorkManager代码施加的硬性限制。
The system instructed your app to stop your work for some reason. This can happen if you exceed the execution deadline of 10 minutes.
[这似乎是最有可能的,但另一个问题可能与here中概述的Android背景限制有关,其中详细说明了与Apps that target Android 8.0 or higher
相关的更改。正如您在编辑中提到的那样,您正在Google Pixel 3, API 28, Android 9
上进行测试,并且可能直接相关。
就解决方案而言,最简单的解决方案尽管令人沮丧,但却是告诉用户他们需要将应用程序置于前台。这样至少可以避免10分钟的间隔。
另一种选择是利用API 29中引入的新
Bubble
API。文档为here,而您可能会感兴趣的文档部分为When a bubble is expanded, the content activity goes through the normal process lifecycle, resulting in the application becoming a foreground process
。制作一个小型的“扩展”视图,并在应用关闭时由用户扩展,这是绕过10分钟计时器的一个不错的替代解决方案。