รองรับผู้ปฏิบัติงานระยะยาว

WorkManager รองรับงานที่ทำงานต่อเนื่องอยู่แล้ว ในกรณีเช่นนี้ WorkManager สามารถส่งสัญญาณไปยังระบบปฏิบัติการว่าควรทำให้กระบวนการทำงานต่อไปได้หากเป็นไปได้ขณะที่งานนี้กำลังดำเนินการ เวิร์กเกอร์เหล่านี้ทำงานได้นานกว่า 10 นาที ตัวอย่าง Use Case สำหรับฟีเจอร์ใหม่นี้ ได้แก่ การอัปโหลดหรือดาวน์โหลดจํานวนมาก (ที่แบ่งเป็นกลุ่มไม่ได้) การคํานวณโมเดล ML ในเครื่อง หรืองานที่สําคัญต่อผู้ใช้ของแอป

เบื้องหลัง WorkManager จะจัดการและเรียกใช้บริการที่ทำงานอยู่เบื้องหน้าในนามของคุณเพื่อดำเนินการ WorkRequest พร้อมกับแสดงการแจ้งเตือนที่กําหนดค่าได้

ตอนนี้ ListenableWorker รองรับ setForegroundAsync() API และ CoroutineWorker รองรับ setForeground() API ที่ระงับ API เหล่านี้ช่วยให้นักพัฒนาแอประบุได้ว่า WorkRequest นี้สำคัญ (จากมุมมองผู้ใช้) หรือทำงานอยู่นาน

ตั้งแต่เวอร์ชัน 2.3.0-alpha03 เป็นต้นไป WorkManager ยังให้คุณสร้าง PendingIntent ได้ด้วย ซึ่งใช้ยกเลิก PendingIntent โดยไม่ต้องลงทะเบียนคอมโพเนนต์ Android ใหม่โดยใช้ createCancelPendingIntent() API แนวทางนี้จะมีประโยชน์อย่างยิ่งเมื่อใช้กับ setForegroundAsync() หรือ setForeground() API ซึ่งสามารถใช้เพื่อเพิ่มการดำเนินการแจ้งเตือนเพื่อยกเลิก Worker

การสร้างและจัดการเวิร์กเกอร์ที่ทำงานต่อเนื่อง

คุณจะใช้วิธีการที่แตกต่างกันเล็กน้อยโดยขึ้นอยู่กับว่าคุณเขียนโค้ดเป็น Kotlin หรือ Java

Kotlin

นักพัฒนาซอฟต์แวร์ Kotlin ควรใช้ CoroutineWorker คุณสามารถใช้วิธีดังกล่าวในเวอร์ชันที่ระงับแทน setForeground() แทนการใช้ setForegroundAsync()

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

   private val notificationManager =
       context.getSystemService(Context.NOTIFICATION_SERVICE) as
               NotificationManager

   override suspend fun doWork(): Result {
       val inputUrl = inputData.getString(KEY_INPUT_URL)
                      ?: return Result.failure()
       val outputFile = inputData.getString(KEY_OUTPUT_FILE_NAME)
                      ?: return Result.failure()
       // Mark the Worker as important
       val progress = "Starting Download"
       setForeground(createForegroundInfo(progress))
       download(inputUrl, outputFile)
       return Result.success()
   }

   private fun download(inputUrl: String, outputFile: String) {
       // Downloads a file and updates bytes read
       // Calls setForeground() periodically when it needs to update
       // the ongoing Notification
   }
   // Creates an instance of ForegroundInfo which can be used to update the
   // ongoing notification.
   private fun createForegroundInfo(progress: String): ForegroundInfo {
       val id = applicationContext.getString(R.string.notification_channel_id)
       val title = applicationContext.getString(R.string.notification_title)
       val cancel = applicationContext.getString(R.string.cancel_download)
       // This PendingIntent can be used to cancel the worker
       val intent = WorkManager.getInstance(applicationContext)
               .createCancelPendingIntent(getId())

       // Create a Notification channel if necessary
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
           createChannel()
       }

       val notification = NotificationCompat.Builder(applicationContext, id)
           .setContentTitle(title)
           .setTicker(title)
           .setContentText(progress)
           .setSmallIcon(R.drawable.ic_work_notification)
           .setOngoing(true)
           // Add the cancel action to the notification which can
           // be used to cancel the worker
           .addAction(android.R.drawable.ic_delete, cancel, intent)
           .build()

       return ForegroundInfo(notificationId, notification)
   }

   @RequiresApi(Build.VERSION_CODES.O)
   private fun createChannel() {
       // Create a Notification channel
   }

   companion object {
       const val KEY_INPUT_URL = "KEY_INPUT_URL"
       const val KEY_OUTPUT_FILE_NAME = "KEY_OUTPUT_FILE_NAME"
   }
}

Java

นักพัฒนาแอปที่ใช้ ListenableWorker หรือ Worker สามารถเรียกใช้ setForegroundAsync() API ซึ่งจะแสดงผลเป็น ListenableFuture<Void> นอกจากนี้ คุณยังโทรไปที่ setForegroundAsync() เพื่ออัปเดตNotificationที่ดำเนินอยู่ได้ด้วย

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

public class DownloadWorker extends Worker {
   private static final String KEY_INPUT_URL = "KEY_INPUT_URL";
   private static final String KEY_OUTPUT_FILE_NAME = "KEY_OUTPUT_FILE_NAME";

   private NotificationManager notificationManager;

   public DownloadWorker(
       @NonNull Context context,
       @NonNull WorkerParameters parameters) {
           super(context, parameters);
           notificationManager = (NotificationManager)
               context.getSystemService(NOTIFICATION_SERVICE);
   }

   @NonNull
   @Override
   public Result doWork() {
       Data inputData = getInputData();
       String inputUrl = inputData.getString(KEY_INPUT_URL);
       String outputFile = inputData.getString(KEY_OUTPUT_FILE_NAME);
       // Mark the Worker as important
       String progress = "Starting Download";
       setForegroundAsync(createForegroundInfo(progress));
       download(inputUrl, outputFile);
       return Result.success();
   }

   private void download(String inputUrl, String outputFile) {
       // Downloads a file and updates bytes read
       // Calls setForegroundAsync(createForegroundInfo(myProgress))
       // periodically when it needs to update the ongoing Notification.
   }

   @NonNull
   private ForegroundInfo createForegroundInfo(@NonNull String progress) {
       // Build a notification using bytesRead and contentLength

       Context context = getApplicationContext();
       String id = context.getString(R.string.notification_channel_id);
       String title = context.getString(R.string.notification_title);
       String cancel = context.getString(R.string.cancel_download);
       // This PendingIntent can be used to cancel the worker
       PendingIntent intent = WorkManager.getInstance(context)
               .createCancelPendingIntent(getId());

       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
           createChannel();
       }

       Notification notification = new NotificationCompat.Builder(context, id)
               .setContentTitle(title)
               .setTicker(title)
               .setSmallIcon(R.drawable.ic_work_notification)
               .setOngoing(true)
               // Add the cancel action to the notification which can
               // be used to cancel the worker
               .addAction(android.R.drawable.ic_delete, cancel, intent)
               .build();

       return new ForegroundInfo(notificationId, notification);
   }

   @RequiresApi(Build.VERSION_CODES.O)
   private void createChannel() {
       // Create a Notification channel
   }
}

เพิ่มประเภทบริการที่ทำงานอยู่เบื้องหน้าไปยังเวิร์กเกอร์ที่ทำงานต่อเนื่อง

หากแอปกำหนดเป้าหมายเป็น Android 14 (API ระดับ 34) ขึ้นไป คุณต้องระบุประเภทบริการที่ทำงานอยู่เบื้องหน้าสำหรับเวิร์กเกอร์ที่ทำงานอยู่นานทั้งหมด หากแอปกำหนดเป้าหมายเป็น Android 10 (API ระดับ 29) ขึ้นไป และมี Worker ที่ทำงานอยู่นานซึ่งจำเป็นต้องเข้าถึงตำแหน่ง ให้ระบุว่า Worker ใช้บริการที่ทำงานอยู่เบื้องหน้าประเภท location

หากแอปกำหนดเป้าหมายเป็น Android 11 (API ระดับ 30) ขึ้นไป และมี Foreground Worker ที่ทำงานอยู่นานซึ่งจำเป็นต้องเข้าถึงกล้องหรือไมโครโฟน ให้ประกาศบริการที่ทำงานอยู่เบื้องหน้าประเภท camera หรือ microphone ตามลำดับ

หากต้องการเพิ่มประเภทบริการที่ทำงานอยู่เบื้องหน้าเหล่านี้ ให้ทำตามขั้นตอนที่อธิบายไว้ในส่วนต่อไปนี้

ประกาศประเภทบริการที่ทำงานอยู่เบื้องหน้าในไฟล์ Manifest ของแอป

ประกาศประเภทบริการที่ทำงานอยู่เบื้องหน้าของ WOrker ในไฟล์ Manifest ของแอป ในตัวอย่างต่อไปนี้ เจ้าหน้าที่ต้องเข้าถึงตำแหน่งและไมโครโฟน

AndroidManifest.xml

<service
   android:name="androidx.work.impl.foreground.SystemForegroundService"
   android:foregroundServiceType="location|microphone"
   tools:node="merge" />

ระบุประเภทบริการที่ทำงานอยู่เบื้องหน้าขณะรันไทม์

เมื่อเรียกใช้ setForeground() หรือ setForegroundAsync() โปรดตรวจสอบว่าคุณได้ระบุประเภทบริการที่ทำงานอยู่เบื้องหน้า

MyLocationAndMicrophoneWorker

Kotlin

private fun createForegroundInfo(progress: String): ForegroundInfo {
   // ...
   return ForegroundInfo(NOTIFICATION_ID, notification,
           FOREGROUND_SERVICE_TYPE_LOCATION or
FOREGROUND_SERVICE_TYPE_MICROPHONE) }

Java

@NonNull
private ForegroundInfo createForegroundInfo(@NonNull String progress) {
   // Build a notification...
   Notification notification = ...;
   return new ForegroundInfo(NOTIFICATION_ID, notification,
           FOREGROUND_SERVICE_TYPE_LOCATION | FOREGROUND_SERVICE_TYPE_MICROPHONE);
}