เมื่อกำหนดWorker
และWorkRequest
แล้ว
ขั้นตอนสุดท้ายคือการจัดคิวงาน วิธีที่ง่ายที่สุดในการจัดคิวงาน
คือการเรียกใช้เมธอด enqueue()
ของ WorkManager โดยส่ง 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 สร้างขึ้นโดยอัตโนมัติ ชื่อที่ไม่ซ้ำจะเชื่อมโยงกับผลงานเพียงรายการเดียวเท่านั้น ซึ่งต่างจากแท็ก
คุณสามารถใช้ผลงานที่ไม่ซ้ำกันกับงานแบบครั้งเดียวและงานที่ทำเป็นระยะได้ คุณสร้างลำดับงานที่ไม่ซ้ำกันได้โดยเรียกใช้เมธอดใดเมธอดหนึ่งต่อไปนี้ ทั้งนี้ขึ้นอยู่กับว่าคุณกำลังกำหนดเวลาให้งานทำซ้ำหรือทำครั้งเดียว
WorkManager.enqueueUniqueWork()
สำหรับงานแบบครั้งเดียวWorkManager.enqueueUniquePeriodicWork()
สำหรับงานเป็นระยะ
ทั้ง 2 วิธีนี้ยอมรับอาร์กิวเมนต์ 3 รายการ
- uniqueWorkName -
String
ที่ใช้เพื่อระบุคำของานที่ไม่ซ้ำกัน - existingWorkPolicy -
enum
ซึ่งบอก WorkManager ว่าต้องทำอะไร หากมีลำดับงานที่ยังไม่เสร็จซึ่งมีชื่อที่ไม่ซ้ำกันนั้นอยู่แล้ว ดูข้อมูลเพิ่มเติมได้ในนโยบายการแก้ปัญหาความขัดแย้ง - work -
WorkRequest
ที่จะกำหนดเวลา
การใช้ผลงานที่ไม่ซ้ำกันจะช่วยให้เราแก้ไขปัญหาการกำหนดเวลาที่ซ้ำกันซึ่งได้กล่าวถึงไปก่อนหน้านี้ได้
Kotlin
val sendLogsWorkRequest =
PeriodicWorkRequestBuilder<SendLogsWorker>(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
ตัวเลือกเหล่านี้ทํางานเหมือนกับ
ตัวเลือก ExistingWorkPolicy ที่เกี่ยวข้อง
การสังเกตงานของคุณ
หลังจากจัดคิวงานแล้ว คุณจะตรวจสอบสถานะได้ทุกเมื่อโดยการค้นหา WorkManager ตาม name
id
หรือตาม tag
ที่เชื่อมโยงกับงานนั้น
Kotlin
// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>
// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>
// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>
Java
// by id
workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo>
// by name
workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>>
// by tag
workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>
การค้นหาจะแสดงListenableFuture
ของออบเจ็กต์ WorkInfo
ซึ่งรวมถึงid
ของงาน แท็กของงาน State
ปัจจุบัน และชุดข้อมูลเอาต์พุตใดๆ ที่ใช้ Result.success(outputData)
รูปแบบ LiveData
และ Flow
ของแต่ละเมธอดช่วยให้คุณสังเกตการเปลี่ยนแปลงของ
WorkInfo
ได้โดยการลงทะเบียน Listener เช่น หากต้องการแสดงข้อความแก่ผู้ใช้เมื่อการดำเนินการบางอย่างเสร็จสมบูรณ์ คุณสามารถตั้งค่าได้ดังนี้
Kotlin
workManager.getWorkInfoByIdFlow(syncWorker.id)
.collect{ 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: ListenableFuture<List<WorkInfo>> = 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();
ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);
คอมโพเนนต์แต่ละรายการ (แท็ก สถานะ หรือชื่อ) ใน WorkQuery
จะAND
ร่วมกับคอมโพเนนต์อื่นๆ ค่าแต่ละค่าในคอมโพเนนต์จะOR
ตัวอย่างเช่น (name1 OR name2
OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)
WorkQuery
ยังใช้ได้กับ LiveData ที่เทียบเท่า
getWorkInfosLiveData()
และ Flow ที่เทียบเท่า getWorkInfosFlow()
การยกเลิกและหยุดงาน
หากไม่ต้องการให้งานที่เข้าคิวไว้ก่อนหน้านี้ทำงานอีกต่อไป คุณสามารถขอให้ระบบยกเลิกงานดังกล่าวได้ 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()
ลบล้างเมธอดนี้เพื่อจัดการการล้างข้อมูลที่อาจเกิดขึ้น ดูข้อมูลเพิ่มเติมได้ที่หยุด
Worker ที่ทำงานอยู่
หยุด Worker ที่ทำงานอยู่
WorkManager อาจหยุดWorker
ที่กำลังทำงานเนื่องจากสาเหตุบางประการ ดังนี้
- คุณขอให้ยกเลิกอย่างชัดเจน (เช่น โดยการโทรหา
WorkManager.cancelWorkById(UUID)
) - ในกรณีของงานที่ไม่ซ้ำกัน
คุณได้จัดคิว
WorkRequest
ใหม่โดยชัดแจ้งด้วยExistingWorkPolicy
ของREPLACE
ระบบจะถือว่าWorkRequest
เก่าถูกยกเลิกทันที - ไม่เป็นไปตามข้อจำกัดของงานอีกต่อไป
- ระบบสั่งให้แอปหยุดการทำงานด้วยเหตุผลบางอย่าง ปัญหานี้อาจเกิดขึ้นหากคุณใช้เวลาดำเนินการเกินกำหนดเวลา 10 นาที ระบบ กำหนดเวลาให้ลองอีกครั้งในภายหลัง
ระบบจะหยุด Worker ของคุณในกรณีต่อไปนี้
คุณควรยกเลิกงานที่กำลังดำเนินการอยู่และปล่อยทรัพยากรที่ Worker ถือครองอยู่ เช่น คุณควรปิดแฮนเดิลที่เปิดอยู่กับฐานข้อมูลและไฟล์ในตอนนี้ คุณมีกลไก 2 อย่างที่ใช้เพื่อทำความเข้าใจว่าเมื่อใดที่ Worker หยุดทำงาน
Callback onStopped()
WorkManager จะเรียกใช้
ListenableWorker.onStopped()
ทันทีที่หยุด Worker แทนที่เมธอดนี้เพื่อปิด
ทรัพยากรที่คุณอาจถือครองอยู่
พร็อพเพอร์ตี้ isStopped()
คุณสามารถเรียกใช้เมธอด
ListenableWorker.isStopped()
เพื่อตรวจสอบว่าหยุด Worker แล้วหรือไม่
หากคุณดำเนินการที่ใช้เวลานานหรือดำเนินการซ้ำๆ ใน
Worker คุณควรตรวจสอบพร็อพเพอร์ตี้นี้บ่อยๆ และใช้เป็นสัญญาณสำหรับ
หยุดงานโดยเร็วที่สุด
หมายเหตุ: WorkManager จะไม่สนใจ
Result
ที่ตั้งค่าโดย Worker
ที่ได้รับสัญญาณ onStop เนื่องจากระบบถือว่า Worker หยุดทำงานแล้ว