การจัดการงาน

เมื่อคุณกำหนด Worker และ WorkRequest ของคุณ ขั้นตอนสุดท้ายคือการจัดคิวงาน วิธีที่ง่ายที่สุดในการจัดคิวงาน คือการเรียกใช้เมธอด WorkManager enqueue() โดยส่งผ่าน WorkRequest ที่คุณ ที่ต้องการวิ่ง

Kotlin

val myWork: WorkRequest = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork)

Java

WorkRequest myWork = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork);

โปรดใช้ความระมัดระวังในการจัดคิวงานเพื่อหลีกเลี่ยงการซ้ำซ้อน ตัวอย่างเช่น แอปอาจพยายามอัปโหลด บันทึกไปยังบริการแบ็กเอนด์ทุกๆ 24 ชั่วโมง หากไม่ระวัง คุณอาจ ต้องเข้าคิวงานเดิมหลายครั้ง แม้ว่างานนั้นจะต้อง เรียกใช้ครั้งเดียว หากต้องการบรรลุเป้าหมายนี้ คุณสามารถตั้งเวลางานให้เป็นงานที่ไม่ซ้ำได้

ผลงานที่ไม่ซ้ำใคร

ผลงานที่ไม่ซ้ำใครคือแนวคิดที่มีประสิทธิภาพที่รับประกันว่าคุณจะได้รับเพียงผลงานเดียว ของการทำงานร่วมกันกับชื่อหนึ่งๆ ต่อครั้ง ชื่อที่ไม่ซ้ำกันแตกต่างจากรหัสตรง เป็นเนื้อหาที่มนุษย์อ่านได้และระบุโดยนักพัฒนาซอฟต์แวร์แทนที่จะสร้างขึ้นโดยอัตโนมัติ โดย WorkManager เลิกชอบ tags ไม่ซ้ำกัน จะเชื่อมโยงกับงานเพียงครั้งเดียว

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

ทั้ง 2 วิธีนี้ยอมรับอาร์กิวเมนต์ 3 แบบ

  • uniqueWorkName - String ที่ใช้เพื่อระบุผลงานโดยไม่ซ้ำกัน อีกครั้ง
  • existingWorkPolicy - enum ที่บอก WorkManager ว่าต้องทำอะไรบ้าง มีห่วงโซ่งานที่ยังไม่เสร็จ ซึ่งมีชื่อไม่ซ้ำนั้นอยู่แล้ว โปรดดู นโยบายการระงับข้อพิพาทสำหรับข้อมูลเพิ่มเติม
  • work - WorkRequest ที่จะกำหนดเวลา

ด้วยการใช้การทำงานเฉพาะ เราสามารถแก้ไขปัญหาการตั้งเวลาซ้ำที่เรากล่าวไว้ก่อนหน้านี้

Kotlin

val sendLogsWorkRequest =
       PeriodicWorkRequestBuilderS<endLogsWorker(>24, TimeUnit.HOURS)
           .setConstraints(Constraints.Builder()
               .setRequiresCharging(true)
               .build()
            )
           .build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
           "sendLogs",
           ExistingPeriodicWorkPolicy.KEEP,
           sendLogsWorkRequest
)

Java

PeriodicWorkRequest sendLogsWorkRequest = new
      PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS)
              .setConstraints(new Constraints.Builder()
              .setRequiresCharging(true)
          .build()
      )
     .build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
     "sendLogs",
     ExistingPeriodicWorkPolicy.KEEP,
     sendLogsWorkRequest);

ทีนี้ หากโค้ดทำงานในขณะที่งาน sendLogs อยู่ในคิว รหัสที่มีอยู่ งานจะถูกเก็บไว้และจะไม่เพิ่มงานใหม่

ลำดับการทำงานที่เฉพาะเจาะจงยังมีประโยชน์ในกรณีที่คุณต้องค่อยๆ สร้าง งานที่ยาวนาน เช่น แอปแก้ไขรูปภาพอาจให้ผู้ใช้เลิกทำ ห่วงโซ่การดำเนินการที่ยาว การดำเนินการเลิกทำแต่ละครั้งอาจใช้เวลาสักครู่ แต่ ตามลำดับที่ถูกต้อง ในกรณีนี้ แอปอาจ สร้างการ "เลิกทำ" ห่วงโซ่ แล้วเพิ่มการดำเนินการเลิกทำแต่ละรายการต่อท้ายเชนตามที่จำเป็น ดูงานเชน เพื่อดูรายละเอียดเพิ่มเติม

นโยบายการแก้ไขข้อขัดแย้ง

เมื่อกำหนดเวลางานที่ไม่ซ้ำกัน คุณต้องแจ้งให้ WorkManager ทราบว่าต้องดำเนินการใดเมื่อใด ก็เกิดข้อขัดแย้ง ซึ่งทำได้โดยส่ง Enum เมื่อจัดคิวงาน

สำหรับงานแบบครั้งเดียว คุณจะต้องจัดเตรียม ExistingWorkPolicy ซึ่ง สนับสนุน 4 ตัวเลือกสำหรับการจัดการข้อขัดแย้ง

  • มี REPLACE อยู่แล้ว ที่จะทำงานชิ้นใหม่ ตัวเลือกนี้จะยกเลิกงานที่มีอยู่
  • KEEP งานที่มีอยู่และ ไม่ต้องสนใจงานใหม่
  • APPEND ทำงานใหม่เพื่อ เมื่องานที่มีอยู่สิ้นสุดลง นโยบายนี้จะทำให้งานใหม่ของคุณ ที่ผูกไว้ไว้กับ งานที่มีอยู่ โดยทำงานหลังจากงานที่มีอยู่เสร็จสิ้น

งานที่มีอยู่แล้วจะกลายเป็นข้อกำหนดเบื้องต้นสำหรับงานใหม่ หากงานที่มีอยู่ เปลี่ยนเป็น CANCELLED หรือ FAILED งานใหม่จะเป็น CANCELLED หรือ FAILED ด้วย หากคุณต้องการให้งานใหม่ทำงานไม่ว่างานที่มีอยู่จะอยู่ในสถานะอะไร ใช้ APPEND_OR_REPLACE แทน

  • APPEND_OR_REPLACE ฟังก์ชันที่คล้ายกับ APPEND เว้นแต่ว่าจะไม่อิงตาม สถานะการทำงานตามเกณฑ์เบื้องต้น หากงานที่มีอยู่คือ CANCELLED หรือ คุณ FAILED งานใหม่จะยังคงทำงานอยู่

สำหรับงานที่ต้องทำประจำ คุณต้องให้ ExistingPeriodicWorkPolicy ซึ่งรองรับ 2 ตัวเลือก ได้แก่ REPLACE และ KEEP ตัวเลือกเหล่านี้ทำงานเหมือนเดิม เป็นคู่หูที่มีอยู่

สังเกตงานของคุณ

หลังจากจัดคิวงานแล้ว คุณจะตรวจสอบสถานะของงานได้ทุกเมื่อด้วยการค้นหา WorkManager โดย name, id หรือโดย tag ที่เกี่ยวข้อง

Kotlin

// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFutureW<orkInfo<>/span>

// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFutureL<istW<orkInfo<>/span>
>
// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFutureL<istW<orkInfo<>/span>
>

Java

// by id
workManager.getWorkInfoById(syncWorker.id); // ListenableFutureW<orkInfo<>/span>

// by name
workManager.getWorkInfosForUniqueWork("sync"); // ListenableFutureL<istW<orkInfo<>/span>
>
// by tag
workManager.getWorkInfosByTag("syncTag"); // ListenableFutureL<istW<orkInfo<>/span>
>

การค้นหาจะแสดงผล ListenableFuture ของออบเจ็กต์ WorkInfo ซึ่งรวมถึง id ของผลงาน แท็ก ของงาน Stateปัจจุบันและข้อมูลเอาต์พุตทั้งหมด ตั้งค่าผ่าน Result.success(outputData)

ตัวแปร LiveData ของแต่ละ จะช่วยให้คุณสังเกตการเปลี่ยนแปลงWorkInfoได้ด้วยการลงทะเบียน ผู้ฟัง เช่น ถ้าต้องการแสดงข้อความให้กับผู้ใช้เมื่อ งานบางชิ้นเสร็จเรียบร้อยแล้ว คุณสามารถตั้งค่าได้ดังนี้

Kotlin

workManager.getWorkInfoByIdLiveData(syncWorker.id)
               .observe(viewLifecycleOwner) { workInfo -
>   if(workInfo?.state == WorkInfo.State.SUCCEEDED) {
       Snackbar.make(requireView(), 
      R.string.work_completed, Snackbar.LENGTH_SHORT)
           .show()
   }
}

Java

workManager.getWorkInfoByIdLiveData(syncWorker.id)
        .observe(getViewLifecycleOwner(), workInfo - >{
    if (workInfo.getState() != null 
&&            workInfo.getState() == WorkInfo.State.SUCCEEDED) {
        Snackbar.make(requireView(),
                    R.string.work_completed, Snackbar.LENGTH_SHORT)
                .show();
   }
});

การค้นหางานที่ซับซ้อน

WorkManager 2.4.0 ขึ้นไปรองรับการค้นหาที่ซับซ้อนสำหรับงานที่มีการจัดคิวโดยใช้ WorkQuery ออบเจ็กต์ รองรับ WorkQuery ค้นหางานโดยใช้ทั้งแท็ก สถานะ และชื่องานที่ไม่ซ้ำกัน

ตัวอย่างต่อไปนี้แสดงวิธีค้นหางานทั้งหมดกับแท็ก “syncTag” ที่อยู่ในสถานะ FAILED หรือ CANCELLED และมีชื่อผลงานที่ไม่ซ้ำกันของ “preProcess” หรือ “sync

Kotlin

val workQuery = WorkQuery.Builder
       .fromTags(listOf("syncTag"))
       .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(listOf("preProcess", "sync")
    )
   .build()

val workInfos: ListenableFutureL<istW<orkInfo >>= workManager.getWorkInfos(workQuery)

Java

WorkQuery workQuery = WorkQuery.Builder
       .fromTags(Arrays.asList("syncTag"))
       .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(Arrays.asList("preProcess", "sync")
     )
    .build();

ListenableFutureL<istW<orkInfo >>workInfos = workManager.getWorkInfos(workQuery);

คอมโพเนนต์แต่ละรายการ (แท็ก สถานะ หรือชื่อ) ใน WorkQuery จะมี AND พร้อมเมธอด อื่นๆ แต่ละค่าในคอมโพเนนต์คือ OR-ed เช่น (name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)

WorkQuery ยังใช้ได้กับเวอร์ชันเทียบเท่า LiveData ด้วย getWorkInfosLiveData()

กำลังยกเลิกและหยุดงาน

หากไม่ต้องการให้งานที่จัดคิวไว้ทำงานก่อนหน้านี้แล้ว คุณสามารถขอให้แสดง จะถูกยกเลิก งานสามารถยกเลิกได้โดยname id หรือtag ที่เกี่ยวข้อง

Kotlin

// by id
workManager.cancelWorkById(syncWorker.id)

// by name
workManager.cancelUniqueWork("sync")

// by tag
workManager.cancelAllWorkByTag("syncTag")

Java

// by id
workManager.cancelWorkById(syncWorker.id);

// by name
workManager.cancelUniqueWork("sync");

// by tag
workManager.cancelAllWorkByTag("syncTag");

ในการทำงานเบื้องหลัง WorkManager จะตรวจสอบ State ของงาน หากงานคือ เสร็จสิ้นแล้ว ไม่มีอะไรเกิดขึ้น มิฉะนั้น สถานะของงานจะเปลี่ยนเป็น CANCELLED และงาน จะไม่ทำงานอีกในอนาคต ช่วง งาน WorkRequest ที่อิงตาม ในงานนี้จะ และเป็น CANCELLED ด้วย

งานอยู่ใน RUNNING ในขณะนี้ รับสายที่ ListenableWorker.onStopped() ลบล้างวิธีนี้เพื่อจัดการการล้างข้อมูลที่อาจเกิดขึ้น ดูการหยุด ผู้กำลังทำงานเพื่อดูข้อมูลเพิ่มเติม

หยุดผู้ปฏิบัติงานที่ทำงานอยู่

มีสาเหตุหลายประการที่ทำให้ WorkManager หยุดการทำงานของ Worker ดังนี้

  • คุณขอยกเลิกอย่างชัดแจ้ง (โดยการโทร WorkManager.cancelWorkById(UUID))
  • ในกรณีที่เป็นผลงานที่ไม่ซ้ำ คุณได้จัดคิว WorkRequest ใหม่อย่างชัดเจน ExistingWorkPolicy จาก REPLACE WorkRequest เดิมจะถูกยกเลิกทันที
  • ไม่เป็นไปตามข้อจำกัดของงานอีกต่อไป
  • ระบบสั่งให้แอปหยุดงานด้วยเหตุผลบางอย่าง วิธีนี้ หากเกินกำหนดเวลา ของการดำเนินการที่ 10 นาที ผลงาน กำหนดเวลาลองอีกครั้งในภายหลัง

ในกรณีเช่นนี้ ผู้ปฏิบัติงานของคุณจะหยุดทำงาน

คุณควรร่วมมือกันล้มเลิกงานใดๆ ที่กำลังทำอยู่และปลด ทรัพยากรที่ผู้ปฏิบัติงานยึดถืออยู่ ตัวอย่างเช่น คุณควรปิด "เปิด" กับฐานข้อมูลและไฟล์ในจุดนี้ มีกลไก 2 แบบ เพื่อทำความเข้าใจว่าผู้ปฏิบัติงานของคุณกำลังจะหยุดงานเมื่อใด

onStopped() Callback

เรียกใช้ WorkManager ListenableWorker.onStopped() ทันทีที่ผู้ปฏิบัติงานหยุดทำงาน ลบล้างเมธอดนี้เพื่อปิด ทรัพยากรใดๆ ที่คุณครอบครองอยู่

พร็อพเพอร์ตี้ isStopped()

คุณสามารถเรียกใช้ ListenableWorker.isStopped() เพื่อตรวจสอบว่าผู้ปฏิบัติงานหยุดทำงานแล้วหรือไม่ หากคุณ การดำเนินการที่ใช้เวลานานหรือซ้ำๆ ใน Worker คุณควร หมั่นตรวจสอบคุณสมบัตินี้และใช้เป็นสัญญาณให้หยุดทำงานโดยเร็วที่สุด ให้มากที่สุด

หมายเหตุ: WorkManager จะไม่สนใจฟังก์ชัน Result ตั้งค่าโดยผู้ปฏิบัติงาน ที่ได้รับสัญญาณ onStop เนื่องจากผู้ปฏิบัติงานได้รับการพิจารณาแล้ว หยุดแล้ว