谷歌最近宣布了新的WorkManager
架构组件。通过在doWork()
类中实现Worker
,可以轻松地安排同步工作,但是如果我想在后台执行一些异步工作呢?例如,我想使用Retrofit进行网络服务调用。我知道我可以提出一个同步网络请求,但是它会阻塞线程,只是感觉不对。对此有何解决办法,还是目前还没有得到支持?
发布于 2018-05-17 18:48:13
默认情况下,WorkManager在后台线程上运行其操作。如果您已经在后台线程上运行,并且需要对WorkManager进行同步(阻塞)调用,请使用同步()来访问这些方法。
因此,如果不使用synchronous()
,则可以安全地从doWork()
执行同步网络调用。从设计的角度来看,这也是一种更好的方法,因为回调是很麻烦的。
尽管如此,如果您确实希望从doWork()
中触发异步作业,则需要暂停执行线程,并在异步作业完成时使用wait/notify
机制(或其他一些线程管理机制,例如Semaphore
)继续执行它。在大多数情况下我都不会推荐。
顺便提一下,WorkManager在阿尔法早期就已经出现了。
发布于 2018-05-19 04:15:26
我使用了一个countdownlatch锁存器,并等待它达到0,这只有在异步回调更新之后才会发生。请参阅以下代码:
public WorkerResult doWork() {
final WorkerResult[] result = {WorkerResult.RETRY};
CountDownLatch countDownLatch = new CountDownLatch(1);
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("collection").whereEqualTo("this","that").get().addOnCompleteListener(task -> {
if(task.isSuccessful()) {
task.getResult().getDocuments().get(0).getReference().update("field", "value")
.addOnCompleteListener(task2 -> {
if (task2.isSuccessful()) {
result[0] = WorkerResult.SUCCESS;
} else {
result[0] = WorkerResult.RETRY;
}
countDownLatch.countDown();
});
} else {
result[0] = WorkerResult.RETRY;
countDownLatch.countDown();
}
});
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return result[0];
}
发布于 2018-10-15 14:27:59
现在有了ListenableWorker,它被设计为异步的。
编辑:下面是一些示例用法的片段。我删掉了一大块我认为没有说明性的代码,所以这里很有可能有一两个小错误。
这是一个任务,它接受字符串photoKey,从服务器检索元数据,做一些压缩工作,然后上传压缩后的照片。这发生在主线程上。以下是我们发送工作请求的方式:
private void compressAndUploadFile(final String photoKey) {
Data inputData = new Data.Builder()
.putString(UploadWorker.ARG_PHOTO_KEY, photoKey)
.build();
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(UploadWorker.class)
.setInputData(inputData)
.setConstraints(constraints)
.build();
WorkManager.getInstance().enqueue(request);
}
在UploadWorker中:
public class UploadWorker extends ListenableWorker {
private static final String TAG = "UploadWorker";
public static final String ARG_PHOTO_KEY = "photo-key";
private String mPhotoKey;
/**
* @param appContext The application {@link Context}
* @param workerParams Parameters to setup the internal state of this worker
*/
public UploadWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
mPhotoKey = workerParams.getInputData().getString(ARG_PHOTO_KEY);
}
@NonNull
@Override
public ListenableFuture<Payload> onStartWork() {
SettableFuture<Payload> future = SettableFuture.create();
Photo photo = getPhotoMetadataFromServer(mPhotoKey).addOnCompleteListener(task -> {
if (!task.isSuccessful()) {
Log.e(TAG, "Failed to retrieve photo metadata", task.getException());
future.setException(task.getException());
return;
}
MyPhotoType photo = task.getResult();
File file = photo.getFile();
Log.d(TAG, "Compressing " + photo);
MyImageUtil.compressImage(file, MyConstants.photoUploadConfig).addOnCompleteListener(compressionTask -> {
if (!compressionTask.isSuccessful()) {
Log.e(TAG, "Could not parse " + photo + " as an image.", compressionTask.getException());
future.set(new Payload(Result.FAILURE));
return;
}
byte[] imageData = compressionTask.getResult();
Log.d(TAG, "Done compressing " + photo);
UploadUtil.uploadToServer(photo, imageData);
future.set(new Payload(Result.SUCCESS));
});
});
return future;
}
}
编辑
根据您在应用程序中使用的内容,还可以扩展RxWorker (如果使用RxJava)或CoroutineWorker (如果使用Coroutines)。它们都是从ListenableWorker延伸而来。
https://stackoverflow.com/questions/50403013
复制相似问题