问题
在使用WorkManage时,故意不设置Future的结果,查看其超时机制原理,发现并不是一个固定的时间段,有时候会几分钟,有时候会立即超时,从而判定任务失败。
那么它的超时机制究竟依赖于什么呢?
探究
其实WorkManager的超时机制就是使用了Future的超时机制。
最终依赖CallbackToFutureAdapter#finalize实现:
1.切入点:WorkerWrapper#runWorker
runExpedited.addListener(new Runnable() {
@Override
public void run() {
try {
runExpedited.get();
Logger.get().debug(TAG,
String.format("Starting work for %s", mWorkSpec.workerClassName));
// Call mWorker.startWork() on the main thread.
mInnerFuture = mWorker.startWork();
future.setFuture(mInnerFuture);
} catch (Throwable e) {
future.setException(e);
}
}
}, mWorkTaskExecutor.getMainThreadExecutor());
// Avoid synthetic accessors.
final String workDescription = mWorkDescription;
future.addListener(new Runnable() {
@Override
@SuppressLint("SyntheticAccessor")
public void run() {
try {
// If the ListenableWorker returns a null result treat it as a failure.
ListenableWorker.Result result = future.get();
if (result == null) {
Logger.get().error(TAG, String.format(
"%s returned a null result. Treating it as a failure.",
mWorkSpec.workerClassName));
} else {
Logger.get().debug(TAG, String.format("%s returned a %s result.",
mWorkSpec.workerClassName, result));
mResult = result;
}
} catch (CancellationException exception) {
// Cancellations need to be treated with care here because innerFuture
// cancellations will bubble up, and we need to gracefully handle that.
Logger.get().info(TAG, String.format("%s was cancelled", workDescription),
exception);
} catch (InterruptedException | ExecutionException exception) {
Logger.get().error(TAG,
String.format("%s failed because it threw an exception/error",
workDescription), exception);
} finally {
onWorkFinished();
}
}
}, mWorkTaskExecutor.getBackgroundExecutor());
上述代码中最重要的代码就是:
// 开始任务
mInnerFuture = mWorker.startWork();
通过Future监听上述任务状态
future.addListener(new Runnable() {
@Override
@SuppressLint("SyntheticAccessor")
public void run() {
try {
// If the ListenableWorker returns a null result treat it as a failure.
ListenableWorker.Result result = future.get();
if (result == null) {
Logger.get().error(TAG, String.format(
"%s returned a null result. Treating it as a failure.",
mWorkSpec.workerClassName));
} else {
Logger.get().debug(TAG, String.format("%s returned a %s result.",
mWorkSpec.workerClassName, result));
mResult = result;
}
} catch (CancellationException exception) {
// Cancellations need to be treated with care here because innerFuture
// cancellations will bubble up, and we need to gracefully handle that.
Logger.get().info(TAG, String.format("%s was cancelled", workDescription),
exception);
} catch (InterruptedException | ExecutionException exception) {
Logger.get().error(TAG,
String.format("%s failed because it threw an exception/error",
workDescription), exception);
} finally {
onWorkFinished();
}
}
}, mWorkTaskExecutor.getBackgroundExecutor());
为了探究其超时机制,在Work中注释掉了设置Future的Result的代码,以此来观察WorkManager的超时机制,或者是Future的超时机制。
public ListenableFuture<Result> startWork() {
return CallbackToFutureAdapter.getFuture(completer -> {
// 省略业务代码
// 注释掉了设置Future的Result的代码
// return completer.set(Result.success());
// 省略业务代码
});
我们发现超时后一定会走到 如下catch中,并打印日志如下
catch (InterruptedException | ExecutionException exception)
Work [ id=1bd795a1-59bd-44b2-920f-2467a1696082, tags={ AllDataWorker, tag_all_data_work_request } ] failed because it threw an exception/error , >> androidx.concurrent.futures.CallbackToFutureAdapter$FutureGarbageCollectedException: The completer object was garbage collected - this future would otherwise never complete. The tag was: AllDataWorker$1@ef1fdd2
然后设置了此任务的状态为Failure
Worker result FAILURE for Work [ id=1bd795a1-59bd-44b2-920f-2467a1696082, tags={ AllDataWorker, tag_all_data_work_request } ]
2.上溯来源,查看future#addListener的实现
@Override
public final void addListener(Runnable listener, Executor executor) {
checkNotNull(listener);
checkNotNull(executor);
Listener oldHead = listeners;
if (oldHead != Listener.TOMBSTONE) {
Listener newNode = new Listener(listener, executor);
do {
newNode.next = oldHead;
if (ATOMIC_HELPER.casListeners(this, oldHead, newNode)) {
return;
}
oldHead = listeners; // re-read
} while (oldHead != Listener.TOMBSTONE);
}
executeListener(listener, executor);
}
3.继续上溯 executeListener的调用,通过debug追踪。最终追溯到CallbackToFutureAdapter#finalize
@Override
protected void finalize() {
SafeFuture<T> localFuture = future;
// Complete the future with an error before any cancellation listeners try to set the
// future.
// Also avoid allocating the exception if we know we won't actually be able to set it.
if (localFuture != null && !localFuture.isDone()) {
localFuture.setException(
new FutureGarbageCollectedException(
"The completer object was garbage collected - this future would "
+ "otherwise never "
+ "complete. The tag was: "
+ tag));
}
if (!attemptedSetting) {
ResolvableFuture<Void> localCancellationFuture = cancellationFuture;
if (localCancellationFuture != null) {
// set is idempotent, so even if this was already invoked it won't run
// listeners twice
localCancellationFuture.set(null);
}
}
}
}
上述代码中的FutureGarbageCollectedException正是我们最初捕获的catch,并打印的日志。
new FutureGarbageCollectedException(
"The completer object was garbage collected - this future would "
+ "otherwise never "
+ "complete. The tag was: "
+ tag));
说明
至此,我们完全明白了超时机制是由CallbackToFutureAdapter#finalize实现的。
对于CallbackToFutureAdapter#finalize方法,我们看下ChatGPT怎么说: