בדיקת ההתקדמות של עובדים ברמת הביניים

ל-WorkManager יש תמיכה מובנית בהגדרה ובמעקב אחר התקדמות ביניים של עובדים. אם תהליך ה-Worker פעל בזמן שהאפליקציה הייתה בחזית, אפשר להציג את המידע הזה למשתמש באמצעות ממשקי API שמחזירים את LiveData של WorkInfo.

ListenableWorker תומך עכשיו ב-API‏ setProgressAsync(), שמאפשר לשמור את ההתקדמות באמצע התהליך. ממשקי ה-API האלה מאפשרים למפתחים להגדיר התקדמות ביניים שאפשר לראות בממשק המשתמש. ההתקדמות מיוצגת על ידי הסוג Data, שהוא מאגר של מאפיינים שאפשר להמיר לפורמט סדרתי (בדומה ל-input ול-output, וחל עליו אותן הגבלות).

אפשר לראות את פרטי ההתקדמות ולעדכן אותם רק בזמן שהכלי ListenableWorker פועל. המערכת מתעלמת מניסיונות להגדיר את ההתקדמות של ListenableWorker אחרי שהיא סיימה את ההרצה שלה.

אפשר גם לעקוב אחרי ההתקדמות באמצעות אחת מהשיטות getWorkInfoBy…() או getWorkInfoBy…LiveData(). השיטות האלה מחזירות מופעים של WorkInfo, שיש להן שיטה חדשה getProgress() שמחזירה Data.

התקדמות העדכון

למפתחי Java שמשתמשים ב-ListenableWorker או ב-Worker, ‏ setProgressAsync() API מחזיר ListenableFuture<Void>. העדכון של ההתקדמות הוא אסינכרוני, כי תהליך העדכון כולל אחסון של פרטי ההתקדמות במסד נתונים. ב-Kotlin, אפשר להשתמש בפונקציית ההרחבה CoroutineWorker של האובייקט setProgress() כדי לעדכן את נתוני ההתקדמות.

בדוגמה הזו מוצג ProgressWorker. הערך של Worker מתחיל מ-0, וכשהפעולה מסתיימת הוא מתעדכן ל-100.

Kotlin

import android.content.Context
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.WorkerParameters
import kotlinx.coroutines.delay

class ProgressWorker(context: Context, parameters: WorkerParameters) :
    CoroutineWorker(context, parameters) {

    companion object {
        const val Progress = "Progress"
        private const val delayDuration = 1L
    }

    override suspend fun doWork(): Result {
        val firstUpdate = workDataOf(Progress to 0)
        val lastUpdate = workDataOf(Progress to 100)
        setProgress(firstUpdate)
        delay(delayDuration)
        setProgress(lastUpdate)
        return Result.success()
    }
}

Java

import android.content.Context;
import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

public class ProgressWorker extends Worker {

    private static final String PROGRESS = "PROGRESS";
    private static final long DELAY = 1000L;

    public ProgressWorker(
        @NonNull Context context,
        @NonNull WorkerParameters parameters) {
        super(context, parameters);
        // Set initial progress to 0
        setProgressAsync(new Data.Builder().putInt(PROGRESS, 0).build());
    }

    @NonNull
    @Override
    public Result doWork() {
        try {
            // Doing work.
            Thread.sleep(DELAY);
        } catch (InterruptedException exception) {
            // ... handle exception
        }
        // Set progress to 100 after you are done doing your work.
        setProgressAsync(new Data.Builder().putInt(PROGRESS, 100).build());
        return Result.success();
    }
}

מעקב אחר ההתקדמות

כדי לראות את פרטי ההתקדמות, משתמשים בשיטות getWorkInfoById ומקבלים הפניה אל WorkInfo.

הנה דוגמה לשימוש ב-getWorkInfoByIdFlow ב-Kotlin וב-getWorkInfoByIdLiveData ב-Java.

Kotlin

WorkManager.getInstance(applicationContext)
      // requestId is the WorkRequest id
      .getWorkInfoByIdFlow(requestId)
      .collect { workInfo: WorkInfo? ->
          if (workInfo != null) {
              val progress = workInfo.progress
              val value = progress.getInt("Progress", 0)
              // Do something with progress information
          }
      }

Java

WorkManager.getInstance(getApplicationContext())
     // requestId is the WorkRequest id
     .getWorkInfoByIdLiveData(requestId)
     .observe(lifecycleOwner, new Observer<WorkInfo>() {
             @Override
             public void onChanged(@Nullable WorkInfo workInfo) {
                 if (workInfo != null) {
                     Data progress = workInfo.getProgress();
                     int value = progress.getInt(PROGRESS, 0)
                     // Do something with progress
             }
      }
});

התבוננות במצב של סיבת ההפסקה

כדי לנפות באגים ולגלות למה Worker הופסק, אפשר לתעד את סיבת ההפסקה על ידי קריאה ל-WorkInfo.getStopReason():

Kotlin

workManager.getWorkInfoByIdFlow(syncWorker.id)
  .collect { workInfo ->
      if (workInfo != null) {
        val stopReason = workInfo.stopReason
        logStopReason(syncWorker.id, stopReason)
      }
  }

Java

  workManager.getWorkInfoByIdLiveData(syncWorker.id)
    .observe(getViewLifecycleOwner(), workInfo -> {
        if (workInfo != null) {
          int stopReason = workInfo.getStopReason();
          logStopReason(syncWorker.id, workInfo.getStopReason());
        }
  });

מידע נוסף על מחזור החיים והמצבים של אובייקטים של Worker זמין במאמר מצבי עבודה.