WorkManager-Android ArchitectureComponents(架構組件)

android-architecture-components/WorkManagerSample/

WorkManager(androidx.work.WorkManager)

androidx.work.WorkManager通過WorkManager API,可以輕鬆安排即使應用程序退出或設備重新啓動也可以運行的可延遲的異步任務。

關鍵功能:

  • 兼容最低API 14
    • 在API 23+ 的設備上使用JobScheduler實現
    • 在API14-22的設備上使用BroadcastReceiver + AlarmManager組合實現
  • 可以添加執行任務的約束條件,例如:網絡是否連接、是否處於充電狀態
  • 可以用於完成一次性、週期性的異步任務
  • 監控管理任務執行
  • 可以將任務串聯起來完成(例如先完成任務A再完成任務B最後完成任務C)
  • 即使是App、手機重啓也能保證執行相關任務

WorkManager被設計用於執行延遲任務,這意味着這些任務不需要被立即執行,並且這些延遲任務在App被殺死或者設備重啓後依然能夠可靠的執行。這麼說有點抽象了,舉兩個這樣任務的例子:

  • 發送App運行的log和分析數據到後端服務器(這個比較像友盟、Bugly這樣的服務會用到)
  • 週期性的和服務器同步數據(例如:筆記類的應用,就可以定期的同步服務器和App的筆記)

WorkManager不適用於完成需要和App生命週期關聯的任務,也不適用於完成需要被立即執行的任務。關於什麼樣的任務適用Android提供的相關API,可以參考下圖(這裏的任務都是指需要後臺執行的任務)

[外鏈圖片轉存失敗(img-d4K58xI9-1566298763317)(https://developer.android.google.cn/images/guide/background/bg-job-choose.svg)]

  • Event 事件 從組件或者Lifecycle類分發出來的生命週期,它們和Activity/Fragment生命週期的事件一一對應。(ON_CREATE,ON_START,ON_RESUME,ON_PAUSE,ON_STOP,ON_DESTROY)

  • State 狀態 當前組件的生命週期狀態(INITIALIZED,DESTROYED,CREATED,STARTED,RESUMED)

說的有點抽象了,看一下下面的圖:

image.png

簡單明瞭的選擇分類,就不做過多解釋了。

由於Android對後臺任務管理的不斷嚴格,在完成後臺任務的時候需要考慮不同API版本對後臺任務的限制。關於如何選擇完成後臺任務的API,可以按如下幾點來考慮:

  • 後臺任務是否需要被立即執行還是可以延遲執行? 例如如果是點擊按鈕獲取網絡數據,那麼這個任務就需要被立即執行。但是如果只是想把log上傳到服務器,那麼這個任務就可以延遲執行,這樣就不會對App運行有影響

  • 完成任務是否需要系統處於某些特定的場景 有些任務可能需要在某些特定的場景下執行,例如手機處於充電模式並且有網絡連接等情況。爲什麼要處於這樣的場景下才完成某些任務呢?如果手機處於充電、熄屏並且連接wifi等情況下,那麼我們就可以完成一些比較耗電耗流量的任務,並且不會對用戶體驗造成任何影響。這樣的任務有可能需要事先存儲需要完成的任務,再集中執行。

  • 任務是否需要在精確的時間被執行 日曆類的應用需要在精確地時間提醒用戶設置的事件,但其他的任務可能就沒有必要在精確地時間執行。通常有可能的情況是:任務A執行完成->執行任務B完成->執行任務C,但是並不需要這些任務在精確地時間(例如下午6:30)執行。

好了,使用workmanager的場景想必大家都瞭解一點了,下面我們看看如何使用WorkManager

如何使用

1.依賴

第一步當然是添加workmanager的依賴啦!!

將以下依賴添加進入你的build.gradle中:

dependencies {
  def work_version = "2.2.0"

    // (Java only)
    implementation "androidx.work:work-runtime:$work_version"

    // Kotlin + coroutines
    implementation "androidx.work:work-runtime-ktx:$work_version"

    // optional - RxJava2 support
    implementation "androidx.work:work-rxjava2:$work_version"
    // optional - Test helpers
    androidTestImplementation "androidx.work:work-testing:$work_version"
  }

2.創建worker子類(即一個後臺任務)

創建一個類繼承worker,重寫dowork()方法,doWork()方法是在WorkManager提供的後臺線程上同步運行。請看下面代碼:

class TestWorker(var context: Context,workParams:WorkerParameters) : Worker(context,workParams){

    val TAG = TestWorker::class.java.simpleName
    var handler = Handler(Looper.getMainLooper())

    //這是在後臺線程運行的
    override fun doWork(): Result {

        handler.post {
            Toast.makeText(context,"測試work是在子線程運行的", Toast.LENGTH_SHORT).show()
        }

        return Result.success()
    }
}

3.配置worker運行的方式和時間

worker定義要做什麼任務,workRequest定義瞭如何以及何時運行任務.任務可能是一次性或定期的,對於一次性的任務,使用OneTimeWorkRequest,對於定期的任務使用PeriodicWorkRequest.

下面是WorkRequest的簡單示例:

var testWorkRequest = OneTimeWorkRequestBuilder<TestWorker>().build()

4.將任務交給系統

之前以及定義了WorkRequest,現在你可以使用WorkManagerenqueue()方法將任務添加到系統計劃中.任務入隊,WorkManager調度執行

WorkManager.getInstance(this).enqueue(testWorkRequest)

進階使用

一.自定義WorkRequest(自定義任務何時,如何執行)

1.任務的限制條件

可以添加約束Constraints來指明任務什麼時候執行,請看一下示例:

 var constraints = Constraints.Builder()
                    .setRequiresBatteryNotLow(true)////執行任務時電池電量不能偏低。
                    .setRequiresCharging(true)////在充電時執行
//                    .setRequiresDeviceIdle(true)////在待機狀態執行
                    .setRequiresStorageNotLow(true)//設備儲存空間足夠時才能執行。
//                    .setTriggerContentMaxDelay(Duration.ZERO)
//                    .setTriggerContentUpdateDelay(Duration.ZERO)
                    .setRequiredNetworkType(NetworkType.NOT_REQUIRED)//對網絡沒要求
                    .build()

                var request = OneTimeWorkRequestBuilder<ConstraintWorker>()
                    .setConstraints(constraints)
                    .build()
                WorkManager.getInstance(this).enqueue(request)

其它的都只是傳入一個boolean值,網絡狀態要複雜點,具體看一下說明:

	/**
     * 指定網絡狀態執行任務
     * NetworkType.NOT_REQUIRED:對網絡沒有要求
     * NetworkType.CONNECTED:網絡連接的時候執行
     * NetworkType.UNMETERED:不計費的網絡比如WIFI下執行
     * NetworkType.NOT_ROAMING:非漫遊網絡狀態
     * NetworkType.METERED:計費網絡比如3G,4G下執行。
     */

2.初始化延時

當沒有約束條件或約束條件都滿足的情況下,系統會直接運行任務,如果不想直接運行,可以通過WorkRequest的setInitialDelay()方法設置執行的初始延時時間.

var request = OneTimeWorkRequest.Builder(InitialDelayWorker::class.java)
                    .setInitialDelay(5, TimeUnit.SECONDS)
                    .build()
                WorkManager.getInstance(this).enqueue(request)

3.重試和後退策略

如果你要求WorkManager重行執行你的任務,你可以在你的Worker中返回Result.retry().你的任務會安排一個默認的退避延時和策略.退避策略定義了後續重試嘗試的後退延遲將如何隨時間增加(這塊有點兒難理解,請接着往下看)

這是可以指定退避策略和延時通過WorkRequest.setBackoffCriteria(@NonNull BackoffPolicy backoffPolicy,
long backoffDelay,
@NonNull TimeUnit timeUnit)
方法.

這裏注意幾點:

  1. 默認延時: 30s
    退避策略BackoffPolicy: BackoffPolicy.EXPONENTIAL (指數)

  2. 退避延時要求最小爲:10s(10秒),最大爲5h(5個小時),設置的時間小於10秒按10秒來算,大於5小時按5小時算

  3. 退避策略解釋(默認延時設置爲10秒):
    BackoffPolicy.EXPONENTIAL (指數)規律: Math.scalb(10, 嘗試次數 - 1) 即 10 × 2^(嘗試次數-1)
    BackoffPolicy.LINEAR (線性)規律: 10 20 30 40 50 即 (10 * 嘗試次數)

WorkRequest中定義的退避延時範圍及默認延時

public abstract class WorkRequest {

     /**
      * The default initial backoff time (in milliseconds) for work that has to be retried.
      */
     public static final long DEFAULT_BACKOFF_DELAY_MILLIS = 30000L;
 
     /**
      * The maximum backoff time (in milliseconds) for work that has to be retried.
      */
     public static final long MAX_BACKOFF_MILLIS = 5 * 60 * 60 * 1000; // 5 hours.
 
     /**
      * The minimum backoff time for work (in milliseconds) that has to be retried.
      */
     public static final long MIN_BACKOFF_MILLIS = 10 * 1000; // 10 seconds.
 
 ....
 }

4.定義任務的輸入/輸出

您的任務可能要求將數據作爲輸入參數傳遞或作爲結果返回。例如,處理上傳圖片的任務需要將圖片的URI作爲輸入參數,並且可能需要將上傳圖片的URL作爲輸出。

注意:Data對象應該很小,值可以是字符串,基本類型或它們的數組變體,Data對象的最大大小限制爲10KB。如果你需要在worker中輸入輸出更多的數據,則應將數據放在其他位置,例如Room數據庫。

Worker類可以通過調用Worker.getInputData()來訪問輸入參數。

Data類還可用於輸出返回值。通過將Data對象包含在Result.success()或Result.failure()中的Result中來返回Data對象,如下所示。

/**
 * |---------------------------------------------------------------------------------------------------------------|
 *  @description:  worker的輸入/輸出數據
 *  @author: East
 *  @date: 2019-08-16
 * |---------------------------------------------------------------------------------------------------------------|
 */
class InputOutputWorker(var context: Context, workParams:WorkerParameters) : Worker(context,workParams){

    val TAG = InputOutputWorker::class.java.simpleName
    var handler = Handler(Looper.getMainLooper())

    //這是在後臺線程運行的
    override fun doWork(): Result {

        val s = inputData.getString("key")

        Log.d(TAG,"接受到的數據爲:$s")
        handler.post {
            Toast.makeText(context,"接受到的數據爲:$s", Toast.LENGTH_SHORT).show()
        }



        //創建需要返回的數據
        var outputData = workDataOf("key" to "this is output data")

        //返回數據
        return Result.success(outputData)
    }
}

5.標記Work

您可以通過爲任何WorkRequest對象分配標記字符串來邏輯地對任務進行分組。這允許您使用特定標記操作任務。例如:

  • WorkManager.getInstance(Context context).cancelAllWorkByTag(String tag) 關閉指定tag的所有任務
  • WorkManager.getInstance(Context context).getWorkInfosByTagLiveData(String tag) 返回一個包含指定tag的所有任務狀態列表的livedata

示例如下:

var request = OneTimeWorkRequestBuilder<TestWorker>()
    .addTag("clean up")
    .build()
    
//關閉所有tag爲clean up的任務
//WorkManager.getInstance(this).cancelAllWorkByTag("clean up")
    
WorkManager.getInstance(this).enqueue(request)

二.Work States and observing work(任務狀態和觀察任務)

1.Work State

隨着work的一生,work會經歷很多狀態,我們來學些下有哪些狀態

  • BLOCKED        如果尚未滿足所有的約束條件時.
  • ENQUEUE        滿足了所有的約束條件時.
  • RUNNING         worker正在被運行時
  • SUCCEEDED   當worker返回Result.success()時,這是一個終極狀態,只有OneTimeWorkRequests可以進入此狀態。
  • FAILED             當worker返回Result.failure()時,這也是一個終極狀態,只有OneTimeWorkRequests可以進入此狀態。後續所有相關聯的worker都會被標記爲FAILED狀態且不會被執行.
  • CANCEL             當明確指定cancel尚未終止的WorkRequest時.

2.Observing your work(觀察你的任務)

Worker的狀態信息在WorkInfo對象中,WorkInfo中包含了work的id,tags,還有它當前的state以及一些輸出數據.

可以通過以下三種方式獲取workInfo:

  • 通過id,  WorkManager.getInstance(Context).getWorkInfoById(UUID) or WorkManager.getInstance(Context).getWorkInfoByIdLiveData(UUID).
  • 通過tag,  WorkManager.getInstance(Context).getWorkInfosByTag(String) or WorkManager.getInstance(Context).getWorkInfosByTagLiveData(String).
  • 通過 unique work name,  WorkManager.getInstance(Context).getWorkInfosForUniqueWork(String) or WorkManager.getInstance(Context).getWorkInfosForUniqueWorkLiveData(String)

示例代碼如下:

var request = OneTimeWorkRequestBuilder<InputOutputWorker>()
                    .addTag("clean up")
                    .build()


WorkManager.getInstance(this).getWorkInfoByIdLiveData(request.id).observe(this, Observer {
    if(it != null && it.state == WorkInfo.State.SUCCEEDED){
        val value = it.outputData.getString("key")
        Log.d(TAG,"work 完成,接收到數據爲:$value")
    }
})

//val listenableFuture = WorkManager.getInstance(this).getWorkInfosByTag("clean up")
//val workInfo = listenableFuture.get()

//WorkManager.getInstance(this).getWorkInfosForUniqueWork("hehe")



WorkManager.getInstance(this).enqueue(request)
//WorkManager.getInstance(this).enqueueUniqueWork("hehe",ExistingWorkPolicy.REPLACE,request)

三.任務鏈

1.介紹任務鏈

WorkManager允許你創建並排隊運行一個任務鏈.

創建任務鏈使用 WorkManager.getInstance(Context).beginWith(OneTimeWorkRequest) or WorkManager.getInstance(Context).beginWith(List<OneTimeWorkRequest>) 會返回一個WorkContinuation

WorkContinuation添加OneTimeWorkRequest使用方法 WorkContinuation.then(OneTimeWorkRequest) or WorkContinuation.then(List<OneTimeWorkRequest>) .會接着返回WorkContinuation的新實例,如果添加List of OneTimeWorkRequests,則他們並行執行.最後調用WorkContinuation.enqueue()方法來排隊運行你的任務鏈.

var request = OneTimeWorkRequestBuilder<TestWorker>().build()
var requestConstraint = OneTimeWorkRequestBuilder<ConstraintWorker>().build()
var requestInputOutputWorker = OneTimeWorkRequestBuilder<InputOutputWorker>().build()

WorkManager.getInstance(this)
	 //workRequest並行運行
    .beginWith(arrayListOf(request,requestConstraint))
    //在之前的workRequst之後運行
    .then(requestInputOutputWorker)
    //最後別忘了enqueue
    .enqueue()

2.Input Mergers

在使用OneTimeWorkRequest的任務鏈時,上一個WorkRequest的輸出Data將會作爲下一個WorkRequest的輸入Data.比如上面示例中request,requestConstraint的輸出Data將會作爲requestInputOutputWorker的輸入Data.

爲了管理來自多個父OneTimeWorkRequests的輸入,WorkManager使用InputMergers需要在WorkRequest中調用他的setInutMerger方法它有兩種不同的類型:

  • OverwritingInputMerger        嘗試將所有輸入的所有keys添加到輸出Data中。如果發生衝突,它會覆蓋先前設置的密鑰。
  • ArrayCreatingInputMerger    嘗試合併輸入,並在必要時創建數組。獲取輸入數據時在dowork()方法中調用 getInputData().getStringArray(String key)方法獲取在鏈中之前執行的workRequest中相同key對應的value值.
var request = OneTimeWorkRequestBuilder<TestWorker>()
    .build()
var requestConstraint = OneTimeWorkRequestBuilder<ConstraintWorker>()
    .build()
var requestInputOutputWorker = OneTimeWorkRequestBuilder<InputOutputWorker>()
    .setInputMerger(ArrayCreatingInputMerger::class.java)
    .build()
	
	
WorkManager.getInstance(this)
    //workRequest並行運行
    .beginWith(arrayListOf(request,requestConstraint))
    //在之前的workRequst之後運行
    .then(requestInputOutputWorker)
    //最後別忘了enqueue
    .enqueue()

InputOutputWorker:

//如果inputMerger是OverwritingInputMerger則 s = "constraintworker"
//val s = inputData.getString("key")

//如果inputMerger是ArrayCreatingInoputMerger則 s = "[testworker,constraintworker]"
val s = inputData.getStringArray("key")

TestWorker

return Result.success(workDataOf("key" to "testworker"))

ConstraintWorker:

 return Result.success(workDataOf("key" to "constraintWorker"))

3.任務鏈的狀態

創建OneTimeWorkRequest任務鏈需要記住的幾件事:

  • 當所有其父OneTimeWorkRequests成功(即返回Result.success())時,依賴OneTimeWorkRequests才從BLOCKED狀態轉化爲ENQUEUED狀態.
  • 當父OneTimeWorkRequest失敗時(即返回Result.failure()),後面所有依賴的OneTimeWorkRequests都會被標記成FAILED狀態
  • 當父OneTimeWorkRequest被取消(即爲canceled狀態),後面所有依賴的OneTimeWorkRequests都會被標記成CANCELED狀態

四.取消和停止任務

  • WorkManager.getInstance(Context).cancelWorkById(workRequest.id)        通過id來取消任務
  • WorkManager.getInstance(Context).cancelAllWorkByTag(String)        通過tag來取消任務
  • WorkManager.getInstance(Context).cancelUniqueWork(String)        通過unique name來取消任務
  • WorkManager.getInstance(Context).cancelAllWork()        取消全部任務

以下情況中你正在運行的worker將被WorkManager停止:

  • 你自己明確取消(例如調用cancelWorkById)
  • 在唯一任務的情況下,您使用REPLACE的ExistingWorkPolicy明確地添加了一個新的WorkRequest。舊的WorkRequest立即被視爲已終止。
  • 任務的constraints(約束)將不再被滿足
  • 系統指示您的應用由於某種原因停止任務。如果超過10分鐘的執行截止日期,就會發生這種情況。這項任務計劃在稍後重試。

這些情況下你會接受到ListenableWorker.onStopped(),調用 ListenableWorker.isStopped()來判斷worker是否停止.

五.定期任務(最短間隔時間15分鐘)

你的應用有些時候會需要定期的執行一些任務,例如:定期備份數據,定期上傳應用日誌等等.

使用PeriodicWorkRequest用來執行定期的任務.

注意:PeriodicWorkRequest最短的間隔時間是15分鐘

PeriodicWorkRequest不能添加到工作鏈中,如果需要工作鏈,請使用OneTimeWorkRequest.關於PeriodicWorkRequest的使用,請看下面的例子.

var constraints = Constraints.Builder()
                    .setRequiresCharging(true)
                    .build()

//過了間隔時間後,也會觀察是否滿足充電的約束條件,是的話纔會執行(最小間隔時間必須大於等於15分鐘)
var request = PeriodicWorkRequestBuilder<TestWorker>(5,TimeUnit.SECONDS)
    .setConstraints(constraints)
    .build()

WorkManager.getInstance(this).enqueue(request)

六.unique work(獨特任務)

tag不一樣unique name是僅和一個work 或 work chain 對應.
id不同的是unique name是開發者可定義的.

創建一個unique work 可以通過 WorkManager.getInstance(Context).enqueueUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest) or WorkManager.getInstance(Context).enqueueUniquePeriodicWork(String, ExistingPeriodicWorkPolicy, PeriodicWorkRequest).

第一個參數是unique name 用來標識WorkRequest的祕鑰

第二個參數是衝突解決策略(如果已經存在了該unique name的work或work chain):

  • REPLACE        關閉之前存在的work或work chain,使用新的work或work chain來替代
  • KEEP        保留之前存在的work或work chain,忽略新的work或work chain
  • APPEND        在已經存在的work或work request完成後再執行新的work或work chain,您不能將ExistingPeriodicWorkPolicy.APPENDPeriodicWorkRequests一起使用。

第三個參數是 WorkRequest

如果你需要創建 unique work chain 使用方法

WorkManager.getInstance(Context).beginUniqueWork(String, ExistingWorkPolicy, OneTimeWorkRequest)

示例代碼:

 btn_unique_work -> {
    var request = PeriodicWorkRequestBuilder<TestWorker>(15,TimeUnit.MINUTES).build()

    WorkManager.getInstance(this).enqueueUniquePeriodicWork("test",ExistingPeriodicWorkPolicy.KEEP,request)
}

btn_unique_work_chain -> {
    var request = OneTimeWorkRequestBuilder<TestWorker>()
        .build()
    var requestConstraint = OneTimeWorkRequestBuilder<ConstraintWorker>()
        .build()
    var requestInputOutputWorker = OneTimeWorkRequestBuilder<InputOutputWorker>()
        .setInputMerger(ArrayCreatingInputMerger::class.java)
        .build()

    WorkManager.getInstance(this)
        .beginUniqueWork("test",ExistingWorkPolicy.REPLACE,arrayListOf(request,requestConstraint))
        .then(requestInputOutputWorker)
        .enqueue()

}

七.自定義WorkManager的配置和初始化

1.默認初始化

默認初始化適用於大多數app,當應用打開時,WorkManager使用自定義的ContentProvider初始化自己,使用默認的Configuration,默認初始化是自動加載,除非你 disable 它.

2.自定義初始化

第一步先禁用默認初始化,在AndroidManifest.xml中使用合併規則:tools:node="remove":

<provider
    android:name="androidx.work.impl.WorkManagerInitializer"
    android:authorities="${applicationId}.workmanager-init"
    tools:node="remove" />

第二步自定義自己的初始化:

確保初始化在Application.onCreate()或ContentProvider.onCreate()中運行。:

/**
 * |---------------------------------------------------------------------------------------------------------------|
 *  @description: 自定義 WorkManager的初始化
 *  @author: East
 *  @date: 2019-08-20
 * |---------------------------------------------------------------------------------------------------------------|
 */
class App : Application() {
    override fun onCreate() {
        super.onCreate()

        //提供自定義的配置
        var config = Configuration.Builder()
            .setMinimumLoggingLevel(Log.INFO)
            .setExecutor(Executors.newSingleThreadExecutor())
            .build()

        //初始化WorkManager
        WorkManager.initialize(this,config)

    }
}

3.按需初始化(WorkManager 2.1.0-alpha01及更高版本中提供了按需初始化。)

爲WorkManager提供自定義初始化的最靈活方法是使用按需初始化。按需初始化允許你僅在需要該組件時初始化WorkManager,加快應用啓動速度.

第一步:編輯AndroidManifest.xml並禁用默認初始化程序。

第二步:讓你的Application類實現Configuration.Provider接口,並提供你自己的Configuration.Provider.getWorkManagerConfiguration()實現

第三步:當您需要使用WorkManager時,請調用方法WorkManager.getInstance(Context)。WorkManager調用應用程序的自定義getWorkManagerConfiguration()方法來發現其配置.(您不需要自己調用WorkManager.initialize()。)

class App : Application(),Configuration.Provider {
    override fun onCreate() {
        super.onCreate()
    }
    
    //使用按需初始化workManager時 需要實現接口
    override fun getWorkManagerConfiguration(): Configuration {
        //提供自定義的配置
        var config = Configuration.Builder()
            .setMinimumLoggingLevel(Log.INFO)
            .setExecutor(Executors.newSingleThreadExecutor())
            .build()
        return config
    }
}

八.在WorkManager中進行線程化

WorkManager提供了4種不同的Work:

1.Worker

workerdowork()方法自動運行在WorkManager的Configuration中定義的Executor中的後臺線程中,請注意,Worker.doWork()是一個同步調用 - 您需要以阻塞方式完成整個後臺工作,並在方法退出時完成它。如果在doWork()中調用異步API並返回Result,則回調可能無法正常運行。要解決這類問題請使用ListenableWorker

2.CoroutineWorker

對於Kotlin用戶,WorkManager爲協同程序提供一流的支持。CoroutineWorker.doWork()此代碼不在Configuration中指定的Executor上運行,相反,它默認爲Dispatchers.Default。您可以通過提供自己的CoroutineContext來自定義它.

/**
 * |---------------------------------------------------------------------------------------------------------------|
 *  @description:  適合kotlin用戶的協同Worker  CoroutineWorker
 *  @author: East
 *  @date: 2019-08-20
 * |---------------------------------------------------------------------------------------------------------------|
 */
class KotlinWorker(var context:Context, params:WorkerParameters) : CoroutineWorker(context,params) {


    //已經過時請在doWork方法中使用withContext來指定任務執行時運行的線程
//    override val coroutineContext: CoroutineDispatcher
//        get() = Dispatchers.IO

    override suspend fun doWork(): Result {
        withContext(Dispatchers.Main){
            Toast.makeText(context,"證明CoroutineWorker可通過CoroutineContext來定義執行線程",Toast.LENGTH_SHORT).show()
        }
        return Result.success()
    }
}

3.RxWorker

我們提供WorkManager和RxJava2之間的互操作性,首先繼承 RxWorker,然後重寫RxWorker.createWork()方法以返回指示執行結果的Single,

public class RxDownloadWorker extends RxWorker {

    public RxDownloadWorker(Context context, WorkerParameters params) {
        super(context, params);
    }

    @Override
    public Single<Result> createWork() {
        return Observable.range(0, 100)
            .flatMap { download("https://www.google.com") }
            .toList()
            .map { Result.success() };
    }
}

請注意,在主線程上調用RxWorker.createWork(),但默認情況下在後臺線程上訂閱返回值。您可以覆蓋RxWorker.getBackgroundScheduler()以更改訂閱線程。

停止RxWorker會正確處理Observers,因此您無需以任何特殊方式處理停止工作。

4.ListenableWorker

ListenableWorkerWorkerCoroutineWorkerRxWorker的父類.

抽象方法ListenableWorker.startWork()返回ResultListenableFuture

如果你想基於異步回調執行一些工作,你會做這樣的事情:

dependencies {
    def futures_version = "1.0.0-rc01"
    implementation "androidx.concurrent:concurrent-futures:$futures_version"
}
/**
 * |---------------------------------------------------------------------------------------------------------------|
 *  @description: worker中執行異步操作
 *  @author: East
 *  @date: 2019-08-20
 * |---------------------------------------------------------------------------------------------------------------|
 */
class AsynchronousWorker(context: Context,params:WorkerParameters) : ListenableWorker(context,params) {



    override fun startWork(): ListenableFuture<Result> {
//        val future = ResolvableFuture.create<Result>()
//        future.set(doWork())
//        return future

        return CallbackToFutureAdapter.getFuture<Result> { completer ->
            //做異步操作
        }

    }


    fun doWork() : Result{
        return Result.success()
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章