最近簡單看了下google推出的框架Jetpack,感受此框架的內容能夠對平時的開發有很大的幫助,也能夠解決不少開發中的問題,對代碼的邏輯和UI界面實現深層解耦,打造數據驅動型UI界面。java
Android Architecture組件是Android Jetpack的一部分,它們是一組庫,旨在幫助開發者設計健壯、可測試和可維護的應用程序,包含一下組件:android
上述時Android Architecture所提供的架構組件,本文將詳細介紹下WorkManger的使用bash
WorkManger是Android Jetpack提供執行後臺任務管理的組件,它適用於須要保證系統即便應用程序退出也會運行的任務,WorkManager API能夠輕鬆指定可延遲的異步任務以及什麼時候運行它們,這些API容許您建立任務並將其交給WorkManager當即運行或在適當的時間運行。網絡
WorkManager根據設備API級別和應用程序狀態等因素選擇適當的方式來運行任務。若是WorkManager在應用程序運行時執行您的任務之一,WorkManager能夠在您應用程序進程的新線程中運行您的任務。若是您的應用程序未運行,WorkManager會選擇一種合適的方式來安排後臺任務 - 具體取決於設備API級別和包含的依賴項,WorkManager可能會使用 JobScheduler,Firebase JobDispatcher或AlarmManager架構
3.一、使用WorkManager以前需先了解幾個類:框架
3.二、工做流程異步
def work_version = "1.0.0-alpha10"
implementation "android.arch.work:work-runtime:$work_version" // use -ktx for Kotlin
androidTestImplementation "android.arch.work:work-testing:$work_version"複製代碼
class TestWorker(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters) {
override fun doWork(): Result {
Log.e("TestWorker", "執行了 doWork() 操做!")
return Result.SUCCESS
}
}複製代碼
val workRequest = OneTimeWorkRequest.Builder(TestWorker::class.java).build()
WorkManager.getInstance().enqueue(workRequest)複製代碼
WorkManager.getInstance().getStatusByIdLiveData(workRequest.id) // 返回LiveData
.observe(this, Observer {
Log.e("TestWorker", it?.state?.name)
if (it?.state!!.isFinished) {
Log.e("TestWorker", "Finish")
}
})複製代碼
從上面執行過程當中看出,回調了Work的三個運行狀態RUNNING、SUCCESSESD、FINISHide
// 在鏈接網絡、插入電源且設備處於空閒時運行
val myConstraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresCharging(true)
.setRequiresDeviceIdle(true)
.build()複製代碼
除了上面設置的約束外,WorkManger還提供瞭如下的約束做爲Work執行的條件:post
配置好Constraints後,建立Work對象性能
val compressionWork = OneTimeWorkRequest.Builder(TestWorker::class.java)
.setConstraints(myConstraints)
.build()複製代碼
執行結果:在爲鏈接網絡時,Work處於阻塞狀態當鏈接網絡後Work當即執行變爲SUCCESSED狀態
WorkManager.getInstance().cancelWorkById(workRequest.id)複製代碼
OneTimeWorkRequestBuilder<MyCacheCleanupWorker>()
.addTag("cleanup")
.build()
/./ 使用:
WorkManager.getInstance().getStatusesByTag("TAG")
WorkManager.getInstance().cancelAllWorkByTag("TAG")複製代碼
val timesRequest = PeriodicWorkRequest.Builder(TestWorker::class.java,10,TimeUnit.SECONDS)
......
.build()複製代碼
WorkManager.getInstance()
.beginWith(workA)
.then(workB)
.then(workC)
.enqueue()複製代碼
執行結果:任務會按照設置的順序依次執行A、B、C
有一點就是WorkManger在執行過程當中,當遇到一個WOrk不成功,則會中止執行,現修改WorkB返回FAILURE狀態,再次運行程序結果以下:
override fun doWork(): Result {
Log.e("Worker", "WorkerB 執行了 doWork() 操做!")
return Result.FAILURE
}複製代碼
代碼執行到WorkB就已經結束了,WorkC並未執行。
WorkManager.getInstance()
.beginWith(workA1, workA2, workA3) // 三個對象將並行
.then(workB) // 執行完3個A後,在執行B
.then(workC1, workC2) //...
.enqueue()複製代碼
// ......繼續建立WorkD 和 WorkE 及相應的Request
val configA_B = WorkManager.getInstance().beginWith(workRequest)
.then(workRequestB)
val configC_D = WorkManager.getInstance().beginWith(workRequestC)
.then(workRequestD)
WorkContinuation.combine(configA_B,configC_D)
.then(workRequestE)
.enqueue()複製代碼
執行結果與上面一致:開始時執行A/C,其他爲阻塞狀態,A/C執行結束後執行B/D,最後執行WoekerE
若是此時把WorkB中返回FAILURE,執行結果也一致執行到WorkerB就結束了,WorkerE不會執行
WorkManager.getInstance().beginUniqueWork("worker", ExistingWorkPolicy.APPEND, workRequest)
//參數:一、工做序列的名稱
二、當有相同名稱序列時採起的策略方式
三、須要執行的Worker複製代碼
* ExistingWorkPolicy.REPLACE:取消現有序列並將其替換爲新序列
* ExistingWorkPolicy.KEEP:保留現有序列並忽略您的新請求
* ExistingWorkPolicy.APPEND:將新序列附加到現有序列,在現有序列的最後一個任務完成後運行新序列的第一個任務
以ExistingWorkPolicy.REPLACE爲例,讓WorkA睡眠3秒,模擬同時運行的狀態:
override fun doWork(): Result {
Log.e("Worker", "WorkerA begin Sleep()!")
Thread.sleep(3000)
Log.e("Worker", "WorkerA 執行了 doWork() 操做!")
return Result.SUCCESS
}複製代碼
Append:兩個都會執行
WorkManager.getInstance().beginUniqueWork("worker", ExistingWorkPolicy.APPEND, workRequest)
.enqueue()
WorkManager.getInstance().beginUniqueWork("worker", ExistingWorkPolicy.APPEND, workRequestB)
.enqueue()複製代碼
運行結果:
REPLACE:只會執行WorkerB
KEEP:只會執行WorkerA
修改WorkerA以下
const val MIN_NUMBER = "minNumber"
const val MAX_NUMBER = "maxNumber"
const val RESULT_CODE = "Result"
class WorkerA(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters) {
private var minNumber = 0
private var maxNumber = 0
override fun doWork(): Result {
minNumber = inputData.getInt(MIN_NUMBER, 0) // 使用InputData獲取傳入的參數
maxNumber = inputData.getInt(MAX_NUMBER, 0)
val result = maxNumber - minNumber // 計算結果
val outData: Data = Data.Builder().putAll(mapOf(RESULT_CODE to result)).build() // 建立返回的數據Data
outputData = outData // 設置返回的數據Data
return Result.SUCCESS
}
}複製代碼
建立Worker並傳遞參數
val map = mapOf(MIN_NUMBER to 5, MAX_NUMBER to 15)
val data = Data.Builder().putAll(map).build() // 建立輸入參數Data
val mathWork = OneTimeWorkRequestBuilder<MathWorker>()
.setInputData(data) // 傳遞參數
.build()複製代碼
觀察任務WorkStatus獲取返回結果
WorkManager.getInstance().getStatusByIdLiveData(workRequest.id)
.observe(this, Observer {
if (it?.state!!.isFinished) {
Log.e("WorkerA", "${it.outputData.getInt(RESULT_CODE, 0)}") // 獲取執行結果
}
})複製代碼
const val NUMBER = "NUMBER"
const val RESULT_B = "RESULT_B"
class WorkerB(context: Context,workerParameters: WorkerParameters) : Worker(context,workerParameters){
override fun doWork(): Result {
val input = inputData.getInt(RESULT_CODE,5) // 獲取第一個Worker返回的結果
Log.e("Worker", "WorkerB 接受數據 input = $input ")
val map = mapOf(RESULT_B to input*input)
outputData = Data.Builder().putAll(map).build() // 設置返回數據
return Result.SUCCESS
}
}
// Activity中監聽WorkerB的執行結果
WorkManager.getInstance().getStatusByIdLiveData(workRequestB.id)
.observe(this, Observer {
if (it?.state!!.isFinished) {
Log.e("WorkerB", "${it.outputData.getInt(RESULT_B, 0)}")
}
})複製代碼
執行結果:對於WorkA依次傳入5和15,在WorkA中計算差值15-5 = 10,因此WorkA中輸出10,那麼鏈式調用的WorkB中接收的就是10,加平方後輸出爲100,輸出Log與分析一致,
到此Android Jetpack組件就介紹完了,從第一篇開始到如今有一個月了,中間斷斷續續總算分析完了,經過對組件的學習發現Android Jetpack組件的推出不只加速了咱們開發的速度,並且避免了程序運行中的一些生命週期、內存問題以及一些性能問題,但願能夠經過這幾篇文章對想學習組件的同窗有所幫助,後續將會使用全部的組件編寫一個客戶端,將全部組件綜合使用。