好早之前,項(xiàng)目中有個(gè)功能項(xiàng)需要?jiǎng)?chuàng)建一個(gè)下載任務(wù)做粤,考慮到和界面的無依賴性怎顾,所以我選用了WorkManager
。在當(dāng)時(shí)來看灾梦,WorkManager還算是Android的一個(gè)新技術(shù)峡钓。而那段項(xiàng)目代碼,也是簡單的使用而已若河。
今天能岩,我們從頭再來重新認(rèn)識(shí)并學(xué)習(xí)一下WorkManager。
簡介
WorkManager is an API that makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or the device restarts.
上面是官方關(guān)于WorkManager
的一句簡要說明萧福,從中可以提出幾個(gè)要點(diǎn):
- WorkManager可以輕松地生成定時(shí)拉鹃、異步的后臺(tái)任務(wù)
- 即使應(yīng)用退出,甚至系統(tǒng)重啟后鲫忍,后臺(tái)任務(wù)仍可以執(zhí)行
WorkManger最小可兼容到API14膏燕,是以替代像JobScheduler、AlarmManger等定時(shí)任務(wù)發(fā)布類而存在的悟民,也是官方推薦使用的
基本使用
依賴
首先坝辫,在相應(yīng)的module的build里,添加必要的庫依賴
dependencies {
def work_version = "2.4.0"
// ....
implementation "androidx.work:work-runtime-ktx:$work_version"
// ....
}
因?yàn)槭莐otlin工程射亏,所以這里添加的是work-runtime-ktx
近忙,Java工程則應(yīng)該用work-runtime
實(shí)現(xiàn)Worker
androidx.work.Worker
A class that performs work synchronously on a background thread provided by WorkManager
Worker就是我們要實(shí)現(xiàn)的用于添加任務(wù)代碼的抽象類
public abstract class Worker extends ListenableWorker {
// Package-private to avoid synthetic accessor.
SettableFuture<Result> mFuture;
@Keep
@SuppressLint("BanKeepAnnotation")
public Worker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
/**
* Override this method to do your actual background processing. This method is called on a
* background thread - you are required to <b>synchronously</b> do your work and return the
* {@link androidx.work.ListenableWorker.Result} from this method. Once you return from this
* method, the Worker is considered to have finished what its doing and will be destroyed. If
* you need to do your work asynchronously on a thread of your own choice, see
* {@link ListenableWorker}.
* <p>
* A Worker is given a maximum of ten minutes to finish its execution and return a
* {@link androidx.work.ListenableWorker.Result}. After this time has expired, the Worker will
* be signalled to stop.
*
* @return The {@link androidx.work.ListenableWorker.Result} of the computation; note that
* dependent work will not execute if you use
* {@link androidx.work.ListenableWorker.Result#failure()} or
* {@link androidx.work.ListenableWorker.Result#failure(Data)}
*/
@WorkerThread
public abstract @NonNull Result doWork();
@Override
public final @NonNull ListenableFuture<Result> startWork() {
mFuture = SettableFuture.create();
getBackgroundExecutor().execute(new Runnable() {
@Override
public void run() {
try {
Result result = doWork();
mFuture.set(result);
} catch (Throwable throwable) {
mFuture.setException(throwable);
}
}
});
return mFuture;
}
}
復(fù)寫doWork
方法竭业,并在其中添加實(shí)際任務(wù)代碼即可。
這里來一個(gè)假任務(wù)及舍,作為測(cè)試:
class DelayWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
override fun doWork(): Result {
Log.d(TAG, "doWork on ${Thread.currentThread().id} started - ${System.currentTimeMillis()}")
// emulated work
Thread.sleep(3000)
Log.d(TAG, "doWork on ${Thread.currentThread().id} ended - ${System.currentTimeMillis()}")
return Result.success()
}
}
WorkRequest
任務(wù)建好后未辆,需要一個(gè)啟動(dòng)任務(wù)的“請(qǐng)求類”,如果需要的話锯玛,還可以添加參數(shù) —— WorkRequest
上場(chǎng)了咐柜。
public abstract class WorkRequest {
// ....
public abstract static class Builder<B extends Builder<?, ?>, W extends WorkRequest> {
// ...
}
// ....
}
可以看出,構(gòu)造WorkRequest更振,使用的是Builder模型炕桨;但WorkRequest和它的builder都是抽象類啊饭尝,別慌肯腕,有抽象,就有實(shí)現(xiàn)钥平。
WorkRequest有兩個(gè)實(shí)現(xiàn):OneTimeWorkRequest
和PeriodicWorkRequest
实撒。望文生義,前者用于非重復(fù)的單個(gè)任務(wù)涉瘾,而后者用于周期重復(fù)性任務(wù)知态。
下面來構(gòu)造一個(gè)非重復(fù)任務(wù):
val request = OneTimeWorkRequestBuilder<DelayWorker>().build()
很簡單,這里用了ktx的擴(kuò)展立叛,實(shí)際上就是用了OneTimeWorkRequest.Builder
來build的负敏。
/**
* Creates a [OneTimeWorkRequest] with the given [ListenableWorker].
*/
inline fun <reified W : ListenableWorker> OneTimeWorkRequestBuilder() =
OneTimeWorkRequest.Builder(W::class.java)
啟動(dòng)任務(wù)
worker和request都有了,接下來就要啟動(dòng)任務(wù)了秘蛇,WorkManager
上場(chǎng):
Log.d(TAG, "enqueue on ${Thread.currentThread().id} ${System.currentTimeMillis()}")
WorkManager.getInstance(applicationContext).enqueue(request)
WorkManager以單例形式存在其做,調(diào)用enqueue
,添加前面創(chuàng)建的request即可赁还。
執(zhí)行結(jié)果
上述任務(wù)的執(zhí)行日志:
2021-01-09 15:46:43.437 15929-15929/com.jacee.examples.workmanager D/JTest: enqueue on 2 1610178403437
2021-01-09 15:46:43.513 15929-15969/com.jacee.examples.workmanager D/JTest: doWork on 4754 started - 1610178403513
2021-01-09 15:46:46.515 15929-15969/com.jacee.examples.workmanager D/JTest: doWork on 4754 ended - 1610178406514
任務(wù)成功異常地在子線程執(zhí)行了妖泄,并耗時(shí)3秒(當(dāng)然,這里是假任務(wù))艘策。
結(jié)語
前面的測(cè)試代碼蹈胡,算是幫我們基本認(rèn)識(shí)了WorkManager,也大概了解了它的基本使用朋蔫。有時(shí)間罚渐,咱再來學(xué)習(xí)WorkManager的其他功能。
本文首發(fā)于 https://jaceedai.github.io/