Androidでワークマネージャを使う


助けてくれたなら、

簡単に説明します.
  • カスタムワーナー
  • OneTimeWorkリクエスト
  • 定期的な要求
  • 作業者のための書き込みテスト( STEP 2およびSTEP 3 )
  • カスタムワーナー


    詳細説明here ワークマネージャ用
    ドキュメントごとに

    By default, WorkManager configures itself automatically when your app starts. If you require more control of how WorkManager manages and schedules work, you can customise the WorkManager configuration.

  • 依存関係をインストールするapp.gradle
  • def work_version = "2.5.0"
    implementation "androidx.work:work-runtime-ktx:$work_version"
    androidTestImplementation "androidx.work:work-testing:$work_version"
  • デフォルトの初期値を削除するAndroidManifest.xml
  • <provider
       android:name="androidx.work.impl.WorkManagerInitializer"
       android:authorities="${applicationId}.workmanager-init"
       tools:node="remove" />
    アプリケーションクラスを作成し、独自のカスタム設定を定義します.
    class TodoApplication() : Application(), Configuration.Provider {
        override fun onCreate() {
          super.onCreate()
          // LATER PUT THE PERIODIC WORK REQUEST HERE
        }
        override fun getWorkManagerConfiguration(): Configuration {
     
          return if (BuildConfig.DEBUG) {
             Configuration.Builder().setMinimumLoggingLevel(Log.DEBUG).build()
          } 
          else {
             Configuration.Builder().setMinimumLoggingLevel(Log.ERROR).build()
          }
        }
    }

    Here, we use Configuration.Provider to extend our TodoApplication, and override the getWorkManagerConfiguration


    この場合、ログレベルを設定します.カスタマイズ可能な一覧の一覧についてはConfiguration.Builder()

    OneTimeWorkリクエスト


    これは、我々のフォルダ構造がどのように見えるかです
    アプリの労働者
    任意の労働者を作成するには、次の手順が必要です.
  • ワーカー(このセクション)は:あなたがバックグラウンドで実行したい実際の作業
  • WorkRequest(ViewModelセクションで作成):これはいくつかの作業を行う要求を表します.
  • ワークマネージャ(上記で作成) :スケジュールWorkRequest そして実行する
  • OndemandBackupWorkerから始めましょう.基本的にはバックエンドにデータを保存することです.
    このファイルにはfileworkerが続き、このファイルはデバイスにファイルを作成し、タイムスタンプを新しく作成したファイルに追加する
    ファイルワーク出力

    OndemandBackupWorker

  • このクラスはCoroutineWorker (小琴コウモリ)
  • 我々は、我々の中断している仕事のためにDowork機能を上書きします
  • override suspend fun doWork(): Result {
        val appContext = applicationContext
        showNotifications("Backing up the data", appContext)
        return try {
           val res = dummyWork()
           val outputData = workDataOf(KEY_ONDEMANDWORKER_RESP to res)
           Result.success(outputData)
        } catch (throwable: Throwable) {
           Timber.e(throwable)
           Result.failure()
        }
    }
    private suspend fun dummyWork(): String {
         // Faking the network call
         sleep()
         return "Completed successfully!"
    }

    Here, we create a dummyWork function, (which puts the thread to sleep) and returns string result.

  • その後、結果を内部に置くworkDataOf (これはデータオブジェクトに対するペアのリストを、キーを使って変換します.
  • この結果/出力はResult.success それは成功した作品を示します
  • エラーが発生した場合、私たちはResult.failure
  • ファイルワーカー

  • このクラスはWorker (バックグラウンドで同期して作業を行う)
  • 私たちは同期作業のためにDowork関数をオーバーライドします
  • override fun doWork(): Result {
    return try {
       val content="Backed up on ${dateFormatter.format(Date())}"
       val outputUri = saveToFile(appContext, content)
       val data=workDataOf(KEY_FILEWORKER_RESP to outputUri.toString())
       Result.success(data)
       
     } catch (throwable: Throwable) {
         Timber.e(throwable)
         Result.failure()
       }
    }

    Here, we create a file using saveToFile, and put in the current timestamp as text into that file

  • その後、結果を内部に置くworkDataOf そして前のように、我々は労働者のResult.success
  • OnDemandBackupViewModel

  • このクラスは、ワークリクエストを作成し、AndroidViewModel .
  • このクラスの中で2つの関数
  • internal fun beginBackup() {
       val constraints = Constraints.Builder()
         .setRequiresStorageNotLow(true)
         .setRequiresBatteryNotLow(true)
         .setRequiredNetworkType(NetworkType.CONNECTED)
         .build()
    var continuation = workManager.beginUniqueWork(
           ONDEMAND_BACKUP_WORK_NAME,
           ExistingWorkPolicy.KEEP,
        OneTimeWorkRequest.from(OnDemandBackupWorker::class.java)
       )
    // BACKUP WORKER
       val backupBuilder = OneTimeWorkRequestBuilder<OnDemandBackupWorker>()
            
      
      backupBuilder.addTag(TAG_BACKUP)
      backupBuilder.setConstraints(constraints)
      continuation = continuation.then(backupBuilder.build())
    // SAVE FILE WORKER
      val saveInFile = OneTimeWorkRequest.Builder(FileWorker::class.java)
          .setConstraints(constraints)
          .addTag(TAG_FILE)
          .build()
      continuation = continuation.then(saveInFile)
      continuation.enqueue()
    }
    
    internal fun cancelBackup() {
       workManager.cancelUniqueWork(ONDEMAND_BACKUP_WORK_NAME)
    }
  • 労働者が実行することになっている制約を指定します(我々のケースでは、ストレージ、バッテリー、インターネット)
  • ViewModelクラス内のWorkManagerのインスタンスを取得します.このインスタンスを使用して、beginUniqueWork
  • Since, we need to chain our work requests, hence we use beginUniqueWork

  • 私たちは私たちの労働者にユニークな名前を与えるExistingWorkPolicy オプションKEEP OndemandBackupWorkerクラスからOneTimeWorkRequestを作成する
  • からの出力beginUniqueWork は作業継続です.
  • 次に、WorkRequestビルダーを作成しますOneTimeWorkRequestBuilder ○○.私たちは、この仕事のためにタグを加えます
  • このリクエストはWorkContinuation
  • 我々は、我々のファイルワークのために最後の2つのステップを繰り返します
  • 最後に、作業リクエストチェインのチェーンをキューに追加する必要があります.これはenqueue
  • Note: For cancelling a work request, we simply call the cancelUniqueWork with the tag (used for creating the work) 


    ワークリクエストの進捗状況の追跡

  • 我々は我々の労働者のためのタグを追加したので、我々はすべてのステータスを得るためにそれらを利用することができますWorkRequest
  • It returns a LiveData それはWorkInfo オブジェクト.WorkInfo の現在の状態に関する詳細を含むオブジェクトですWorkRequest
  • internal val backupDataInfo: LiveData<List<WorkInfo>> = workManager
            .getWorkInfosByTagLiveData(TAG_BACKUP)

    Here, TAG_BACKUP is our tag, specified previously


    定期的な要求


    Note: PeriodicBackupWorker is the same like FileWorker (only difference is the file content)

  • この作業はキャンセルされるまで複数回実行されます.最初の実行は即座に実行されますConstraints 会う.
  • 次の実行は期間間隔の間に起こります.
  • アプリケーションクラスに移動し、PeriodicWorkRequest.Builder
  • val constraints = Constraints.Builder()
        .setRequiresStorageNotLow(true)
        .setRequiresBatteryNotLow(true)
        .setRequiredNetworkType(NetworkType.UNMETERED)
        .build()
    val periodicBackup = PeriodicWorkRequestBuilder<PeriodicBackupWorker>(1, TimeUnit.DAYS)
        .addTag(TAG_PERIODIC_BACKUP)
        .setConstraints(constraints)
        .build()
    WorkManager.getInstance(this).enqueueUniquePeriodicWork(
         PERIODIC_BACKUP_WORK_NAME,
         ExistingPeriodicWorkPolicy.KEEP,
         periodicBackup
     )
  • 必要に応じて制約を指定します
  • 使用PeriodicWorkRequestBuilder , 我々の作成PeriodicWorkRequest
  • 時間間隔は1日1回として指定されます.
  • Periodic work has a minimum interval of 15 minutes. Also if your periodic work has constraints, it will not execute until the constraints are met, even if the delay between periods has been met.

  • 我々は、我々のenqueuePeriodicWorkRequest 使用enqueueUniquePeriodicWork , 作業方針の維持Keep
  • The normal lifecycle of a PeriodicWorkRequest is ENQUEUED -> RUNNING -> ENQUEUED


    従業員の筆記試験



    我々は、現在我々の労働者のためにテストを書きます:OnDemandBackupWorker and PeriodicBackupWorker

    OndemandBackupWorkerテスト

  • テストクラスの作成OnDemandBackupWorkerTest
  • 我々のクラスについて注釈を付けるAndroidJUnit4 これは、単一のクラスのテストを駆動するものです.
  • @RunWith(AndroidJUnit4::class)
    class OnDemandBackupWorkerTest {
     private lateinit var context: Context
     private lateinit var executor: Executor
     @Before
     fun setUp() {
         context = ApplicationProvider.getApplicationContext()
         executor = Executors.newSingleThreadExecutor()
     }
     @Test
     fun testOnDemandBackupWorker() {
        val worker = TestListenableWorkerBuilder<OnDemandBackupWorker> (context).build()
        
       runBlocking {
         val result = worker.doWork()
         assertTrue(result is ListenableWorker.Result.Success)
       }
     }
    }
  • 我々はコンテキストと実行者の内部を初期化しますsetUp と単一のテストを書くtestOnDemandBackupWorker
  • 以来、私たちのondemandbackupworkerはCoroutineworkerです、我々は使用しますTestListenableWorkerBuilder これは基本的にListenableWorker テストに使用します.
  • 次に、私たちはdoWork 内部runBlocking , (テスト用にメインスレッドに同期してテストを実行します).
  • OndemandBackupWorkerテスト

    定期的なバックアップテスト

  • テストクラスの作成PeriodicBackupWorkerTest
  • 前と同じように、我々は2010年に初期化setUp メソッドと書き込み
  • // TEST 1
    @Test
    fun testPeriodicBackUpWorker() {
       val worker = TestWorkerBuilder<PeriodicBackupWorker>(
            context = context,
            executor = executor
        ).build()
       val result = worker.doWork()
       assertTrue(result is ListenableWorker.Result.Success)
    }
  • 以来、我々の定期的なbackupworker労働者は、我々の使用TestWorkerBuilder これは基本的にWorker テストに使用します.
  • 次に、私たちはdoWork そして、Result.success
  • 2回目のテストでは、周期的な作業状態がENQUEUED
  • // TEST 2
    @Test
    fun testIfPeriodicBackupRunning() {
     WorkManagerTestInitHelper.initializeTestWorkManager(context)
     
     val testDriver = WorkManagerTestInitHelper.getTestDriver(context)
     val workManager = WorkManager.getInstance(context)
     val constraints = Constraints.Builder()
         .setRequiresStorageNotLow(true)
         .setRequiresBatteryNotLow(true)
         .setRequiredNetworkType(NetworkType.UNMETERED)
         .build()
     val request =
         PeriodicWorkRequestBuilder<PeriodicBackupWorker> (repeatInterval=24, TimeUnit.HOURS)
             .setConstraints(constraints)
             .build()
     workManager.enqueue(request).result.get()
     with(testDriver) {
          this?.setPeriodDelayMet(request.id)
          this?.setAllConstraintsMet(request.id)
     }
     val workInfo = workManager.getWorkInfoById(request.id).get()
     assertEquals(workInfo.state, WorkInfo.State.ENQUEUED)
    }
  • 利用するWorkManagerTestInitHelper 初期化に役立つWorkManager テストのために.
  • 制約を設定し、StreamWorkRequestを作成し、WorkManagerインスタンスを使用してEnqueueを取得します
  • 次に、私たちはtestDriver ステータスがそうであるならば、制約を満たして、アサートするためにENQUEUED
  • PeriodicBackupWorkerTestSource code.
    助けてくれたなら、