การย้ายข้อมูลจาก Firebase JobDispatcher ไปยัง WorkManager

WorkManager เป็นไลบรารีสำหรับการจัดกำหนดการและดำเนินการทำงานเบื้องหลังที่เลื่อนเวลาได้ ใน Android เราแนะนำให้ใช้แทน Firebase JobDispatcher คำแนะนำต่อไปนี้จะช่วยแนะนำขั้นตอนการย้ายข้อมูล Firebase การนำ JobDispatcher ไปใช้ใน WorkManager

การตั้งค่า Gradle

หากต้องการนำเข้าไลบรารี WorkManager ลงในโปรเจ็กต์ Android ให้เพิ่มพารามิเตอร์ ทรัพยากร Dependency ที่แสดงใน การเริ่มต้นใช้งาน WorkManager

จาก JobService ไปยังผู้ปฏิบัติงาน

FirebaseJobDispatcher ใช้คลาสย่อยของ JobService เป็นจุดเริ่มต้นสำหรับกำหนด งานที่ต้องทำ คุณอาจ โดยใช้ JobService โดยตรง หรือใช้ SimpleJobService

JobService จะมีลักษณะดังนี้

Kotlin

import com.firebase.jobdispatcher.JobParameters
import com.firebase.jobdispatcher.JobService

class MyJobService : JobService() {
    override fun onStartJob(job: JobParameters): Boolean {
        // Do some work here
        return false // Answers the question: "Is there still work going on?"
    }
    override fun onStopJob(job: JobParameters): Boolean {
        return false // Answers the question: "Should this job be retried?"
    }
}

Java

import com.firebase.jobdispatcher.JobParameters;
import com.firebase.jobdispatcher.JobService;

public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters job) {
        // Do some work here

        return false; // Answers the question: "Is there still work going on?"
    }

    @Override
    public boolean onStopJob(JobParameters job) {
        return false; // Answers the question: "Should this job be retried?"
    }
}

หากคุณกำลังใช้ SimpleJobService คุณจะลบล้าง onRunJob() ได้ ซึ่งแสดงผลประเภท @JobResult int

ความแตกต่างหลักคือเมื่อคุณใช้ JobService โดยตรง, onStartJob() ในเทรดหลัก และเป็นความรับผิดชอบของแอปในการนำออก ไปยังชุดข้อความพื้นหลังได้ ในทางกลับกัน ถ้าคุณใช้ SimpleJobService บริการดังกล่าวมีหน้าที่รับผิดชอบในการดำเนินงานของคุณ เทรดพื้นหลัง

WorkManager มีแนวคิดที่คล้ายกัน หน่วยพื้นฐานของงานใน WorkManager คือ ListenableWorker มี ประเภทย่อยที่มีประโยชน์อื่นๆ ของผู้ปฏิบัติงาน เช่น Worker RxWorker และ CoroutineWorker (เมื่อ ที่ใช้ Kotlin coroutines)

JobService แมปกับ ListenableWorker

หากคุณใช้ JobService โดยตรง ผู้ปฏิบัติงานที่แมปด้วยจะเป็น ListenableWorker ถ้าคุณใช้ SimpleJobService คุณควรใช้ Worker แทน

ให้ใช้ตัวอย่างด้านบน (MyJobService) และดูว่าเราจะแปลงได้อย่างไร เป็น ListenableWorker

Kotlin

import android.content.Context
import androidx.work.ListenableWorker
import androidx.work.ListenableWorker.Result
import androidx.work.WorkerParameters
import com.google.common.util.concurrent.ListenableFuture

class MyWorker(appContext: Context, params: WorkerParameters) :
    ListenableWorker(appContext, params) {

    override fun startWork(): ListenableFuture<ListenableWorker.Result> {
        // Do your work here.
        TODO("Return a ListenableFuture<Result>")
    }

    override fun onStopped() {
        // Cleanup because you are being stopped.
    }
}

Java

import android.content.Context;
import androidx.work.ListenableWorker;
import androidx.work.ListenableWorker.Result;
import androidx.work.WorkerParameters;
import com.google.common.util.concurrent.ListenableFuture;

class MyWorker extends ListenableWorker {

  public MyWorker(@NonNull Context appContext, @NonNull WorkerParameters params) {
    super(appContext, params);
  }

  @Override
  public ListenableFuture<ListenableWorker.Result> startWork() {
    // Do your work here.
    Data input = getInputData();

    // Return a ListenableFuture<>
  }

  @Override
  public void onStopped() {
    // Cleanup because you are being stopped.
  }
}

หน่วยการทำงานพื้นฐานของ WorkManager คือ ListenableWorker เหมือน JobService.onStartJob(), มีการเรียก startWork() ในเทรดหลัก ที่นี่ MyWorker ใช้งาน ListenableWorker และแสดงผลอินสแตนซ์ของ ListenableFuture ซึ่งใช้เพื่อส่งสัญญาณแจ้งการทำงานเสร็จสมบูรณ์แบบไม่พร้อมกัน คุณควรเลือก สร้างชุดข้อความของตัวเองที่นี่

ListenableFuture ที่นี่จะแสดงประเภท ListenableWorker.Result ในท้ายที่สุด ซึ่งอาจเป็น Result.success(), Result.success(Data outputData), Result.retry(), Result.failure() หรือ Result.failure(Data outputData) สำหรับ โปรดดูข้อมูลเพิ่มเติมในหน้าข้อมูลอ้างอิงสำหรับ ListenableWorker.Result

มีการเรียก onStopped() เพื่อส่งสัญญาณว่า ListenableWorker จำเป็นต้องหยุด เนื่องจากไม่สามารถบรรลุข้อจำกัดได้ (เช่น เนื่องจาก เครือข่าย ไม่สามารถใช้งานได้อีกต่อไป) หรือเนื่องจากเมธอด WorkManager.cancel…() คือ โทรออก อาจมีการเรียก onStopped() หากระบบปฏิบัติการตัดสินใจปิด ทำงานด้วยเหตุผลบางอย่าง

SimpleJobService แมปไปยังผู้ปฏิบัติงาน

เมื่อใช้ SimpleJobService ผู้ปฏิบัติงานด้านบนจะมีลักษณะดังต่อไปนี้

Kotlin

import android.content.Context;
import androidx.work.Data;
import androidx.work.ListenableWorker.Result;
import androidx.work.Worker;
import androidx.work.WorkerParameters;


class MyWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        TODO("Return a Result")
    }

    override fun onStopped() {
        super.onStopped()
        TODO("Cleanup, because you are being stopped")
    }
}

Java

import android.content.Context;
import androidx.work.Data;
import androidx.work.ListenableWorker.Result;
import androidx.work.Worker;
import androidx.work.WorkerParameters;

class MyWorker extends Worker {

  public MyWorker(@NonNull Context appContext, @NonNull WorkerParameters params) {
    super(appContext, params);
  }

  @Override
  public Result doWork() {
    // Do your work here.
    Data input = getInputData();

    // Return a ListenableWorker.Result
    Data outputData = new Data.Builder()
        .putString(Key, value)
        .build();
    return Result.success(outputData);
  }

  @Override
  public void onStopped() {
    // Cleanup because you are being stopped.
  }
}

ที่นี่ doWork() จะส่งกลับอินสแตนซ์ของ ListenableWorker.Result เพื่อส่งสัญญาณแจ้งงาน การทำงานเสร็จพร้อมกัน ซึ่งคล้ายกับ SimpleJobService ซึ่งกำหนดเวลา งานในชุดข้อความในเบื้องหลัง

JobBuilder แมปไปยัง WorkRequest

FirebaseJobBuilder ใช้ Job.Builder เพื่อแสดงข้อมูลเมตาของ Job เครื่องมือจัดการงาน ใช้ WorkRequest เพื่อเติมเต็มบทบาทนี้

WorkManager มี WorkRequest 2 ประเภทดังนี้ OneTimeWorkRequest และ PeriodicWorkRequest

หากคุณกำลังใช้ Job.Builder.setRecurring(true) คุณควร สร้าง PeriodicWorkRequest ใหม่ หรือไม่เช่นนั้น คุณควรใช้ OneTimeWorkRequest

มาดูกันว่าการตั้งเวลา Job ที่ซับซ้อนด้วย FirebaseJobDispatcher อาจมีอะไรบ้าง มีลักษณะดังนี้

Kotlin

val input: Bundle = Bundle().apply {
    putString("some_key", "some_value")
}

val job = dispatcher.newJobBuilder()
    // the JobService that will be called
    .setService(MyService::class.java)
    // uniquely identifies the job
    .setTag("my-unique-tag")
    // one-off job
    .setRecurring(false)
    // don't persist past a device reboot
    .setLifetime(Lifetime.UNTIL_NEXT_BOOT)
    // start between 0 and 60 seconds from now
    .setTrigger(Trigger.executionWindow(0, 60))
    // don't overwrite an existing job with the same tag
    .setReplaceCurrent(false)
    // retry with exponential backoff
    .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)

    .setConstraints(
        // only run on an unmetered network
        Constraint.ON_UNMETERED_NETWORK,
        // // only run when the device is charging
        Constraint.DEVICE_CHARGING
    )
    .setExtras(input)
    .build()

dispatcher.mustSchedule(job)

Java

Bundle input = new Bundle();
input.putString("some_key", "some_value");

Job myJob = dispatcher.newJobBuilder()
    // the JobService that will be called
    .setService(MyJobService.class)
    // uniquely identifies the job
    .setTag("my-unique-tag")
    // one-off job
    .setRecurring(false)
    // don't persist past a device reboot
    .setLifetime(Lifetime.UNTIL_NEXT_BOOT)
    // start between 0 and 60 seconds from now
    .setTrigger(Trigger.executionWindow(0, 60))
    // don't overwrite an existing job with the same tag
    .setReplaceCurrent(false)
    // retry with exponential backoff
    .setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
    // constraints that need to be satisfied for the job to run
    .setConstraints(
        // only run on an unmetered network
        Constraint.ON_UNMETERED_NETWORK,
        // only run when the device is charging
        Constraint.DEVICE_CHARGING
    )
    .setExtras(input)
    .build();

dispatcher.mustSchedule(myJob);

หากต้องการดำเนินการดังกล่าวด้วย WorkManager คุณจะต้องทำดังนี้

  • สร้างข้อมูลอินพุตที่สามารถใช้เป็นอินพุตสำหรับ Worker
  • สร้าง WorkRequest ด้วยข้อมูลอินพุตและข้อจำกัดที่คล้ายกับ ที่กำหนดไว้ข้างต้นสำหรับ FirebaseJobDispatcher
  • จัดคิว WorkRequest

การตั้งค่าอินพุตสำหรับผู้ปฏิบัติงาน

FirebaseJobDispatcher ใช้ Bundle เพื่อส่งข้อมูลอินพุตไปยัง JobService WorkManager ใช้ Data แทน สไตรค์ ที่จะกลายเป็น

Kotlin

import androidx.work.workDataOf
val data = workDataOf("some_key" to "some_val")

Java

import androidx.work.Data;
Data input = new Data.Builder()
    .putString("some_key", "some_value")
    .build();

การตั้งค่าข้อจำกัดสำหรับผู้ปฏิบัติงาน

FirebaseJobDispatcher ใช้ Job.Builder.setConstaints(...) มากำหนดข้อจำกัดในงาน WorkManager ใช้ Constraints แทน

Kotlin

import androidx.work.*

val constraints: Constraints = Constraints.Builder().apply {
    setRequiredNetworkType(NetworkType.CONNECTED)
    setRequiresCharging(true)
}.build()

Java

import androidx.work.Constraints;
import androidx.work.Constraints.Builder;
import androidx.work.NetworkType;

Constraints constraints = new Constraints.Builder()
    // The Worker needs Network connectivity
    .setRequiredNetworkType(NetworkType.CONNECTED)
    // Needs the device to be charging
    .setRequiresCharging(true)
    .build();

การสร้าง WorkRequest (OneTime หรือ Periodic)

คุณควรใช้เพื่อสร้าง OneTimeWorkRequest และ PeriodicWorkRequest OneTimeWorkRequest.Builder และ PeriodicWorkRequest.Builder

หากต้องการสร้าง OneTimeWorkRequest ซึ่งคล้ายกับ Job ด้านบน คุณควร ให้ทำดังนี้

Kotlin

import androidx.work.*
import java.util.concurrent.TimeUnit

val constraints: Constraints = TODO("Define constraints as above")
val request: OneTimeWorkRequest =
     // Tell which work to execute
     OneTimeWorkRequestBuilder<MyWorker>()
         // Sets the input data for the ListenableWorker
        .setInputData(input)
        // If you want to delay the start of work by 60 seconds
        .setInitialDelay(60, TimeUnit.SECONDS)
        // Set a backoff criteria to be used when retry-ing
        .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30000, TimeUnit.MILLISECONDS)
        // Set additional constraints
        .setConstraints(constraints)
        .build()

Java

import androidx.work.BackoffCriteria;
import androidx.work.Constraints;
import androidx.work.Constraints.Builder;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.OneTimeWorkRequest.Builder;
import androidx.work.Data;

// Define constraints (as above)
Constraints constraints = ...
OneTimeWorkRequest request =
    // Tell which work to execute
    new OneTimeWorkRequest.Builder(MyWorker.class)
        // Sets the input data for the ListenableWorker
        .setInputData(inputData)
        // If you want to delay the start of work by 60 seconds
        .setInitialDelay(60, TimeUnit.SECONDS)
        // Set a backoff criteria to be used when retry-ing
        .setBackoffCriteria(BackoffCriteria.EXPONENTIAL, 30000, TimeUnit.MILLISECONDS)
        // Set additional constraints
        .setConstraints(constraints)
        .build();

ความแตกต่างที่สำคัญในที่นี้คืองานของ WorkManager จะยังคงอยู่ตลอดทั่วทั้ง อุปกรณ์จะรีบูตโดยอัตโนมัติ

หากต้องการสร้าง PeriodicWorkRequest คุณจะต้องทำดังนี้

Kotlin

val constraints: Constraints = TODO("Define constraints as above")
val request: PeriodicWorkRequest =
PeriodicWorkRequestBuilder<MyWorker>(15, TimeUnit.MINUTES)
    // Sets the input data for the ListenableWorker
    .setInputData(input)
    // Other setters
    .build()

Java

import androidx.work.BackoffCriteria;
import androidx.work.Constraints;
import androidx.work.Constraints.Builder;
import androidx.work.NetworkType;
import androidx.work.PeriodicWorkRequest;
import androidx.work.PeriodicWorkRequest.Builder;
import androidx.work.Data;

// Define constraints (as above)
Constraints constraints = ...

PeriodicWorkRequest request =
    // Executes MyWorker every 15 minutes
    new PeriodicWorkRequest.Builder(MyWorker.class, 15, TimeUnit.MINUTES)
        // Sets the input data for the ListenableWorker
        .setInputData(input)
        . // other setters (as above)
        .build();

การกำหนดเวลางาน

ตอนนี้คุณก็ได้กำหนด Worker และ WorkRequest แล้ว คุณก็พร้อมที่จะ กำหนดเวลางาน

ทุก Job ที่กำหนดไว้ด้วย FirebaseJobDispatcher มี tag ซึ่งใช้เพื่อ ระบุ Job อย่างไม่ซ้ำกัน และยังทำให้แอปพลิเคชัน ตัวจัดตารางเวลาหากอินสแตนซ์นี้ของ Job ใช้เพื่อแทนที่สำเนาที่มีอยู่ของ Job โดยโทรไปที่ setReplaceCurrent

Kotlin

val job = dispatcher.newJobBuilder()
    // the JobService that will be called
    .setService(MyService::class.java)
    // uniquely identifies the job
    .setTag("my-unique-tag")
    // don't overwrite an existing job with the same tag
    .setRecurring(false)
    // Other setters...
    .build()

Java

Job myJob = dispatcher.newJobBuilder()
    // the JobService that will be called
    .setService(MyJobService.class)
    // uniquely identifies the job
    .setTag("my-unique-tag")
    // don't overwrite an existing job with the same tag
    .setReplaceCurrent(false)
    // other setters
    // ...

dispatcher.mustSchedule(myJob);

เมื่อใช้ WorkManager คุณจะได้ผลลัพธ์เดียวกันได้โดยใช้ enqueueUniqueWork() และ enqueueUniquePeriodicWork() API (เมื่อใช้ OneTimeWorkRequest และ PeriodicWorkRequest ตามลำดับ) สำหรับข้อมูลเพิ่มเติม โปรดดูหน้าอ้างอิงสำหรับ WorkManager.enqueueUniqueWork() และ WorkManager.enqueueUniquePeriodicWork()

ซึ่งจะมีลักษณะดังนี้

Kotlin

import androidx.work.*

val request: OneTimeWorkRequest = TODO("A WorkRequest")
WorkManager.getInstance(myContext)
    .enqueueUniqueWork("my-unique-name", ExistingWorkPolicy.KEEP, request)

Java

import androidx.work.ExistingWorkPolicy;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;

OneTimeWorkRequest workRequest = // a WorkRequest;
WorkManager.getInstance(myContext)
    // Use ExistingWorkPolicy.REPLACE to cancel and delete any existing pending
    // (uncompleted) work with the same unique name. Then, insert the newly-specified
    // work.
    .enqueueUniqueWork("my-unique-name", ExistingWorkPolicy.KEEP, workRequest);

กำลังยกเลิกงาน

เมื่อใช้ FirebaseJobDispatcher คุณจะยกเลิกการทำงานได้โดยใช้สิ่งต่อไปนี้

Kotlin

dispatcher.cancel("my-unique-tag")

Java

dispatcher.cancel("my-unique-tag");

เมื่อใช้ WorkManager คุณจะใช้สิ่งต่อไปนี้ได้

Kotlin

import androidx.work.WorkManager
WorkManager.getInstance(myContext).cancelUniqueWork("my-unique-name")

Java

import androidx.work.WorkManager;
WorkManager.getInstance(myContext).cancelUniqueWork("my-unique-name");

กำลังเริ่มต้น WorkManager

ตามปกติ WorkManager จะเริ่มต้นทำงานเองโดยใช้ ContentProvider หากต้องการควบคุมวิธีการจัดระเบียบและกำหนดเวลาของ WorkManager ได้มากขึ้น คุณสามารถดำเนินการต่อไปนี้ ปรับแต่งการกำหนดค่าและการเริ่มต้น WorkManager ได้