AndroidX Work Library 正在取消操作,看似无故
AndroidX Work Library is canceling operations, seemingly without reason
我正在使用 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();
}
然后它会触发此 class,其中 运行 是所有后台服务操作:
public class MyServiceSampleForWhosebug extends Worker {
private Context context;
private WorkerParameters params;
public MyServiceSampleForWhosebug(@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.MyServiceSampleForWhosebug } ] 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.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)
当这种情况随机发生时,我真的只是盯着我的 phone 而根本没有与之互动。我不是要 运行 其他应用程序,也不是要占用 CPU 其他东西。我从来没有看到我自己的任何堆栈跟踪,也没有直接的问题或原因是可见的。
那么问题来了,这里发生了什么,在没有任何挑衅的情况下随机停止 Worker 服务? 为什么会随机停止操作?
谢谢大家
编辑 1
我确实测试过删除网络约束要求行,认为这可能会导致问题,而且我确实看到它甚至在那之后发生,所以我认为这不是问题所在。
我正在 Google Pixel 3、API 28、Android 9 上进行测试,但无论 API 级别(支持的最低级别为 21)显示了相同的问题。
编辑 2
- 我尝试通过 class 扩展
ListenableWorker
而不是 Worker
来重写 class 以处理异步方法,但这并没有解决问题。
您很可能面临 2 个问题之一。
首先,假设您的后台服务运行时间超过 10 分钟 can take anywhere from 3-30 minutes depending on the size and length of the video in question
,您可能会 运行 进入由WorkManager 代码。
在 docs here 他们说:The system instructed your app to stop your work for some reason. This can happen if you exceed the execution deadline of 10 minutes.
这似乎是最有可能的,但另一个问题可能与 Android 概述的背景限制有关 here,其中详细说明了与 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
。制作一个小型 'expanded' 视图并让用户在应用程序关闭时展开它是绕过 10 分钟计时器的一个很好的替代解决方案。
我们现在可以 运行 超过 10 分钟,至少根据工作管理器版本 Support for long-running workers :
WorkManager 2.3.0-alpha02 adds first-class support for long running
workers. In such cases, WorkManager can provide a signal to the OS
that the process should be kept alive if possible while this work is
executing. These Workers can run longer than 10 minutes. Example
use-cases for this new feature include bulk uploads or downloads (that
cannot be chunked), crunching on an ML model locally, or a task that's
important to the user of the app.
link 共享中给出了示例。请检查一下。
我正在使用 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();
}
然后它会触发此 class,其中 运行 是所有后台服务操作:
public class MyServiceSampleForWhosebug extends Worker {
private Context context;
private WorkerParameters params;
public MyServiceSampleForWhosebug(@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.MyServiceSampleForWhosebug } ] 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.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)
当这种情况随机发生时,我真的只是盯着我的 phone 而根本没有与之互动。我不是要 运行 其他应用程序,也不是要占用 CPU 其他东西。我从来没有看到我自己的任何堆栈跟踪,也没有直接的问题或原因是可见的。
那么问题来了,这里发生了什么,在没有任何挑衅的情况下随机停止 Worker 服务? 为什么会随机停止操作?
谢谢大家
编辑 1
我确实测试过删除网络约束要求行,认为这可能会导致问题,而且我确实看到它甚至在那之后发生,所以我认为这不是问题所在。
我正在 Google Pixel 3、API 28、Android 9 上进行测试,但无论 API 级别(支持的最低级别为 21)显示了相同的问题。
编辑 2
- 我尝试通过 class 扩展
ListenableWorker
而不是Worker
来重写 class 以处理异步方法,但这并没有解决问题。
您很可能面临 2 个问题之一。
首先,假设您的后台服务运行时间超过 10 分钟 can take anywhere from 3-30 minutes depending on the size and length of the video in question
,您可能会 运行 进入由WorkManager 代码。
在 docs here 他们说:The system instructed your app to stop your work for some reason. This can happen if you exceed the execution deadline of 10 minutes.
这似乎是最有可能的,但另一个问题可能与 Android 概述的背景限制有关 here,其中详细说明了与 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
。制作一个小型 'expanded' 视图并让用户在应用程序关闭时展开它是绕过 10 分钟计时器的一个很好的替代解决方案。
我们现在可以 运行 超过 10 分钟,至少根据工作管理器版本 Support for long-running workers :
WorkManager 2.3.0-alpha02 adds first-class support for long running workers. In such cases, WorkManager can provide a signal to the OS that the process should be kept alive if possible while this work is executing. These Workers can run longer than 10 minutes. Example use-cases for this new feature include bulk uploads or downloads (that cannot be chunked), crunching on an ML model locally, or a task that's important to the user of the app.
link 共享中给出了示例。请检查一下。