在 WorkManager 中處理非同步任務
WorkManager 是 Android Jetpack 中的新元件,用於負責管理後臺任務。關於這個元件的介紹就不多說了,網上到處都是,這裡分享一下在 WorkManager 中處理非同步任務的方法。
我們知道,在 WorkManager 中,處理任務的方式是建立一個繼承自Worker
的任務類,實現doWork()
方法,並在這個方法中實現我們自己的任務,然後返回Result.success()
或Result.failure()
來表示任務執行成功或者失敗。在這裡,doWork()
方法中的任務應該是同步的,這是很自然的,因為doWork()
方法本身就是在子執行緒中執行,因此可以在doWork()
方法中同步執行耗時操作。
但是些情況,我們想要執行的是非同步任務,在 WorkManager 中,有兩種比較好的處理非同步任務的方案。
RxWorker
很多時候我們會使用 RxJava 來處理資料。幸運的是,我們可以使用 RxWorker 來處理非同步任務。
dependencies { ... implementation "android.arch.work:work-runtime:1.0.0-beta05" implementation "android.arch.work:work-rxjava2:1.0.0-beta05" }
然後,將之前整合 Work 的類改為繼承RxWorker
,然後實現createWork()
方法,基本結構如下:
public class AsyncWorker extends RxWorker { public AsyncWorker(Context appContext, WorkerParameters workerParams) { super(appContext, workerParams); } @Override public Single<Result> createWork() { return remoteService.getMySingleResponse() .doOnSuccess(new Consumer() { @Override public void accept(Object object) throws Exception { // 處理任務 } }) .map(new Function() { @Override public Object apply(Object object) throws Exception { return Result.success(); } }) .onErrorReturn(new Function() { @Override public Object apply(Object object) throws Exception { return Result.failure(); } }); } }
很簡單是吧?有一點要注意的是,createWork()
方法預設是在主執行緒中執行的,如果 10 分鐘沒有結束任務,就會自動取消。
ListenableWorker
當我們去檢視 RxWorker 的原始碼時,就可以發現它是繼承了 ListenableWorker 類,其實 Worker 也是通過繼承 ListenableWorker 實現的。 因此,我們可以通過自定義 ListenableWorker 來實現相同的功能。
看一下 Worker 的原始碼,很簡單:
public abstract class Worker extends ListenableWorker { SettableFuture<Result> mFuture; public Worker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); } @WorkerThread public abstract @NonNull Result doWork(); @Override public final @NonNull ListenableFuture<Result> startWork() { mFuture = SettableFuture.create(); getBackgroundExecutor().execute(new Runnable() { @Override public void run() { Result result = doWork(); mFuture.set(result); } }); return mFuture; } }
可以裡面主要使用了SettableFuture
這個類,在startWork()
裡面先建立了SettableFuture
物件,然後開了一個子執行緒,在子執行緒裡面執行doWork()
方法,完了就使用mFuture.set()
方法將 Result 返回。
因此我們也可以模仿 Worker 類的寫法,來實現自己的非同步處理,簡單地模板程式碼如下:
public class AsyncWorker extends ListenableWorker { private SettableFuture<Result> mFuture; public AsyncWorker(Context appContext,WorkerParameters workerParams) { super(appContext, workerParams); } @Override public ListenableFuture<Result> startWork() { mFuture = SettableFuture.create(); doSomeAsyncWork(new AsyncListener() { @Override public void success() { mFuture.set(Result.success()); } @Override public void fail() { mFuture.set(Result.failure()); } }); return mFuture; } }