Bạn đăng ký một tác vụ mỗi sáu giờ rồi đợi nó chạy đúng các mốc 00:00, 06:00, 12:00 và 18:00. Khi máy tiết kiệm pin hoặc không đáp ứng ràng buộc, log xuất hiện vào lúc khác. Vấn đề có thể nằm ở kỳ vọng về scheduler, chưa chắc là code Worker bị lỗi.
Bài này tạo tác vụ chỉ ghi một dòng log để quan sát việc lập lịch. Tài liệu Android được đọc ngày 25/10/2026. Code dùng API WorkManager đã được rà theo tài liệu; chưa build APK hoặc chạy trên thiết bị trong lượt biên tập. Không có kết quả đo thời điểm thực thi thực tế trong bài.
1. Hiểu hợp đồng của periodic work
Theo hướng dẫn định nghĩa WorkRequest, periodic work có khoảng lặp tối thiểu 15 phút và thời điểm chạy phụ thuộc ràng buộc cùng tối ưu của hệ thống. Nếu điều kiện chưa đạt, một lượt có thể bị trễ hoặc bỏ qua trong khoảng tương ứng.
Tham chiếu PeriodicWorkRequest còn nêu lần đầu có thể chạy ngay hoặc khi constraints được đáp ứng. Vì vậy, tham số sáu giờ không có nghĩa là tác vụ đầu tiên luôn đợi đủ sáu giờ, cũng không tự neo lịch vào một giờ địa phương.
WorkManager phù hợp khi công việc chấp nhận thời điểm không chính xác. Nếu yêu cầu sản phẩm là một hành động đúng giờ theo đồng hồ, hãy làm rõ yêu cầu và chọn cơ chế Android phù hợp sau khi đọc giới hạn nền tảng. Đừng tự bù bằng cách giảm periodic interval xuống một phút.
2. Một Worker chẩn đoán không có nghiệp vụ giả
Trong module Android đã có dependency androidx.work:work-runtime theo phiên bản dự án, tạo file Kotlin. Đổi package mẫu cho phù hợp namespace của bạn. Hướng dẫn bắt đầu WorkManager mô tả Worker và phương thức doWork trên background thread.
package com.example.workdemo
import android.content.Context
import android.util.Log
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.Worker
import androidx.work.WorkerParameters
import androidx.work.WorkManager
import java.util.concurrent.TimeUnit
class PeriodicLogWorker(
appContext: Context,
params: WorkerParameters
) : Worker(appContext, params) {
override fun doWork(): Result {
Log.i("PeriodicDemo", "Executed request id=$id")
return Result.success()
}
}
fun schedulePeriodicDemo(context: Context) {
val constraints = Constraints.Builder()
.setRequiresCharging(true)
.build()
val request = PeriodicWorkRequestBuilder<PeriodicLogWorker>(
6, TimeUnit.HOURS
).setConstraints(constraints).build()
WorkManager.getInstance(context.applicationContext)
.enqueueUniquePeriodicWork(
"aedev-periodic-log-demo",
ExistingPeriodicWorkPolicy.KEEP,
request
)
}
fun cancelPeriodicDemo(context: Context) {
WorkManager.getInstance(context.applicationContext)
.cancelUniqueWork("aedev-periodic-log-demo")
}
Gọi schedulePeriodicDemo từ một điểm khởi tạo có chủ đích trong ứng dụng thử. Worker chỉ log ID của request, không đồng bộ catalog, upload dữ liệu hay giả vờ hoàn thành nghiệp vụ chưa được viết. Ràng buộc đang sạc được chọn để bạn dễ quan sát ảnh hưởng của constraints.
3. Chống đăng ký lặp bằng tên công việc
Nếu mỗi lần mở màn hình đều enqueue một periodic request mới không có tên unique, bạn có thể tạo nhiều lịch độc lập. Tài liệu quản lý work mô tả enqueueUniquePeriodicWork và chính sách KEEP để giữ công việc hiện có thay vì thêm bản mới cùng tên.
Điều đó cũng có mặt cần lưu ý: sửa sáu giờ thành mười hai giờ rồi gọi lại với KEEP không có nghĩa cấu hình đang lưu đã được thay theo. Khi cần đổi lịch, hãy chọn chính sách cập nhật được phiên bản WorkManager của dự án hỗ trợ và kiểm tra kết quả. Đừng đổi tên unique chỉ để né xung đột nếu bạn chưa xử lý lịch cũ.
Tên unique nên thể hiện một loại công việc và phạm vi cần thiết. Nếu thật sự có nhiều tài khoản hoặc nhiều tập dữ liệu, quyết định phạm vi ở mức thiết kế thay vì nối mọi ID vào tên rồi để số lịch tăng không kiểm soát.
4. Quan sát đúng trạng thái
Khi một lượt trả Result.success, periodic request vẫn tiếp tục chu kỳ. Tham chiếu API mô tả vòng đời bình thường là ENQUEUED, RUNNING rồi ENQUEUED, thay vì hoàn tất vĩnh viễn ở SUCCEEDED như một công việc một lần.
Đọc WorkInfo theo unique name và đối chiếu log có timestamp trong môi trường thử. Ghi phiên bản Android, WorkManager, điều kiện sạc và trạng thái tiết kiệm pin. Những dữ kiện này giúp phân biệt việc chưa đủ điều kiện với việc Worker đã chạy nhưng xử lý bên trong thất bại.
Kiểm tra và lỗi thường gặp
Trước tiên, đăng ký một lần khi thiết bị đáp ứng điều kiện sạc. Sau đó gọi lại hàm và kiểm tra không xuất hiện nhiều periodic request độc lập cùng mục đích. Tiếp tục thử thay đổi điều kiện sạc, đưa app vào nền và quan sát theo thời gian; không coi log chậm vài phút là bằng chứng chắc chắn có bug.
Nếu chưa thấy log, kiểm tra constraints, trạng thái work và cách khởi tạo WorkManager của dự án. Nếu đã đổi interval nhưng hành vi không đổi, rà chính sách KEEP. Nếu test đang đợi trạng thái SUCCEEDED cuối cùng cho periodic work, sửa kỳ vọng kiểm thử theo vòng đời của loại request đó.
Sau bài học, gọi cancelPeriodicDemo để bỏ đúng công việc thử. Không dùng lệnh hủy toàn bộ work của app chỉ để dọn một fixture, vì các công việc khác có thể đang phục vụ tính năng thật.
Kết luận
PeriodicWorkRequest mô tả công việc lặp có thể trì hoãn, không phải một lịch đồng hồ chính xác. Bắt đầu bằng Worker chẩn đoán, dùng unique work có chủ đích và quan sát constraints trước khi thêm nghiệp vụ đồng bộ thật.



