Android WorkManager 2026: คู่มือฉบับสมบูรณ์ Background Tasks, Constraints และคำถามสัมภาษณ์งาน
เรียนรู้ Android WorkManager สำหรับการรัน background tasks พร้อม constraints, chaining และ CoroutineWorker รวมถึงคำถามสัมภาษณ์งานสำหรับ Android developer

Android WorkManager จัดการงาน background ที่สามารถเลื่อนเวลาได้และรับประกันการทำงาน แม้หลังจากแอปพลิเคชันรีสตาร์ทหรืออุปกรณ์รีบูต ในฐานะส่วนหนึ่งของ Android Jetpack นั้น WorkManager 2.11.2 (เวอร์ชันเสถียร, มีนาคม 2026) มี API แบบรวมที่ทำงานบน API 23+ โดยเลือก implementation ที่ดีที่สุด (JobScheduler, AlarmManager หรือ Firebase JobDispatcher) ตาม API level ของอุปกรณ์
ใช้ WorkManager สำหรับงานที่ต้องการการรับประกันการทำงาน: อัปโหลด log, ซิงค์ข้อมูล, ประมวลผลรูปภาพ สำหรับงานที่ต้องทำทันทีและไม่จำเป็นต้องคงอยู่เมื่อ process ตาย ให้ใช้ Kotlin Coroutines แทน
การตั้งค่า WorkManager 2.11 ในโปรเจกต์ Kotlin
ก่อนเขียน worker ใดๆ ต้องประกาศ dependency ก่อน WorkManager 2.11+ ต้องการ minSdk 23 และ compileSdk 33
dependencies {
val workVersion = "2.11.2"
implementation("androidx.work:work-runtime-ktx:$workVersion")
// Optional: for testing
androidTestImplementation("androidx.work:work-testing:$workVersion")
}Artifact work-runtime-ktx รวม Kotlin extensions และการสนับสนุน Coroutine ผ่าน CoroutineWorker ไม่จำเป็นต้องกำหนดค่าเพิ่มเติมสำหรับการใช้งานพื้นฐาน: WorkManager จะเริ่มต้นตัวเองผ่าน ContentProvider
การสร้าง Worker อย่างง่ายด้วย doWork()
คลาส Worker override doWork() และคืนค่า Result ระบบรันเมธอดนี้บน background thread
class SyncWorker(
context: Context,
params: WorkerParameters
) : Worker(context, params) {
override fun doWork(): Result {
// Read input data
val userId = inputData.getString("user_id") ?: return Result.failure()
return try {
// Perform sync operation
val syncService = SyncService.getInstance(applicationContext)
syncService.syncUserData(userId)
Result.success()
} catch (e: IOException) {
// Retry on network errors
Result.retry()
} catch (e: Exception) {
// Permanent failure
Result.failure()
}
}
}มีผลลัพธ์ที่เป็นไปได้สามแบบ: Result.success() หมายถึงเสร็จสิ้น, Result.failure() หยุดการลองใหม่, และ Result.retry() จัดกำหนดการใหม่ตามนโยบาย backoff
การใช้ CoroutineWorker สำหรับ Suspend Functions
เมื่องานเกี่ยวข้องกับ suspend functions (การเรียก Retrofit, การ query Room) CoroutineWorker ช่วยกำจัด callback ที่ซ้อนกัน
class UploadWorker(
context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
val imageUri = inputData.getString("image_uri")
?: return Result.failure()
// Progress reporting (visible in WorkInfo observers)
setProgress(workDataOf("status" to "compressing"))
val compressed = ImageCompressor.compress(imageUri)
setProgress(workDataOf("status" to "uploading"))
return try {
val response = ApiClient.imageService.upload(compressed)
val outputData = workDataOf("url" to response.imageUrl)
Result.success(outputData)
} catch (e: HttpException) {
if (e.code() in 500..599) Result.retry()
else Result.failure()
}
}
}CoroutineWorker.doWork() รันบน Dispatchers.Default หากต้องการเปลี่ยน dispatcher ให้ใช้ withContext() ภายในฟังก์ชัน
การกำหนด Constraints สำหรับการทำงานแบบมีเงื่อนไข
Constraints ป้องกันไม่ให้งานรันจนกว่าเงื่อนไขจะเป็นไปตามที่กำหนด ซึ่งช่วยประหยัดแบตเตอรี่และหลีกเลี่ยงการพยายามที่ล้มเหลว
fun scheduleUpload(context: Context, imageUri: String) {
val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.UNMETERED) // WiFi only
.setRequiresBatteryNotLow(true)
.setRequiresStorageNotLow(true)
.build()
val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>()
.setConstraints(constraints)
.setInputData(workDataOf("image_uri" to imageUri))
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
Duration.ofMinutes(1)
)
.addTag("upload")
.build()
WorkManager.getInstance(context)
.enqueueUniqueWork(
"upload_$imageUri",
ExistingWorkPolicy.KEEP,
uploadRequest
)
}Constraints ที่มีให้ใช้งานรวมถึงประเภทเครือข่าย (CONNECTED, UNMETERED, METERED, NOT_ROAMING), ระดับแบตเตอรี่, สถานะการชาร์จ, พื้นที่จัดเก็บ และสถานะ idle ของอุปกรณ์ WorkManager 2.10+ ยังยอมรับ NetworkRequest แบบ raw สำหรับการควบคุมเครือข่ายที่ละเอียดยิ่งขึ้น
คำถามสัมภาษณ์ที่พบบ่อยคือเมื่อใดควรใช้ KEEP เทียบกับ REPLACE ใน enqueueUniqueWork ตัวเลือก KEEP จะละเว้นคำขอใหม่หากงานที่มีชื่อเดียวกันมีอยู่แล้ว ในขณะที่ REPLACE จะยกเลิกงานที่มีอยู่และเริ่มต้นใหม่ ใช้ KEEP สำหรับการอัปโหลดที่การทำซ้ำสิ้นเปลือง bandwidth และใช้ REPLACE สำหรับการซิงค์ที่ข้อมูลล่าสุดเท่านั้นที่สำคัญ
การเชื่อมต่อ Work Requests ด้วย then() และ combine()
Workflow ที่ซับซ้อนต้องการการทำงานแบบลำดับและแบบขนาน WorkManager เชื่อมต่อ work requests โดยใช้ beginWith() และ then()
fun processAndUploadImages(context: Context, imageUris: List<String>) {
val workManager = WorkManager.getInstance(context)
// Parallel compression workers
val compressRequests = imageUris.map { uri ->
OneTimeWorkRequestBuilder<CompressWorker>()
.setInputData(workDataOf("uri" to uri))
.build()
}
// Single upload worker runs after all compressions complete
val uploadRequest = OneTimeWorkRequestBuilder<BatchUploadWorker>()
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.build()
// Cleanup runs after upload, regardless of success
val cleanupRequest = OneTimeWorkRequestBuilder<CleanupWorker>()
.build()
workManager
.beginWith(compressRequests) // Parallel
.then(uploadRequest) // Sequential
.then(cleanupRequest) // Sequential
.enqueue()
}Output จาก parallel workers จะรวมเข้ากับ ArrayCreatingInputMerger โดยค่าเริ่มต้น Worker ถัดไปจะได้รับคู่ key-value ทั้งหมด โดยจะสร้าง array สำหรับ key ที่ซ้ำกัน
พร้อมที่จะพิชิตการสัมภาษณ์ Android แล้วหรือยังครับ?
ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ
การกำหนดเวลา Periodic Work ด้วย PeriodicWorkRequest
PeriodicWorkRequest ทำงานซ้ำๆ โดยมีช่วงเวลาขั้นต่ำ 15 นาที (Android บังคับใช้ข้อจำกัดนี้)
fun scheduleDailySync(context: Context) {
val syncRequest = PeriodicWorkRequestBuilder<SyncWorker>(
repeatInterval = 6,
repeatIntervalTimeUnit = TimeUnit.HOURS,
flexTimeWindow = 30,
flexTimeUnit = TimeUnit.MINUTES
)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build()
)
.addTag("periodic_sync")
.build()
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
"daily_sync",
ExistingPeriodicWorkPolicy.UPDATE,
syncRequest
)
}Flex window อนุญาตให้ WorkManager รวมงานกับ job อื่นๆ เพื่อปรับปรุงประสิทธิภาพแบตเตอรี่ ช่วงเวลา 6 ชั่วโมงพร้อม flex 30 นาทีหมายความว่าการทำงานจะเกิดขึ้นระหว่าง 5:30 ถึง 6:00 หลังจากการรันครั้งก่อน
การสังเกตสถานะงานด้วย LiveData และ Flow
WorkManager เปิดเผยสถานะงานผ่าน WorkInfo สามารถสังเกตได้โดยใช้ LiveData หรือ Kotlin Flow
class UploadViewModel(application: Application) : AndroidViewModel(application) {
private val workManager = WorkManager.getInstance(application)
// Flow-based observation
fun observeUpload(workId: UUID): Flow<WorkInfo?> {
return workManager.getWorkInfoByIdFlow(workId)
}
// Check if any upload is running
val activeUploads: Flow<List<WorkInfo>> =
workManager.getWorkInfosByTagFlow("upload")
.map { workInfos ->
workInfos.filter { it.state == WorkInfo.State.RUNNING }
}
}
// In Compose UI
@Composable
fun UploadProgress(workId: UUID, viewModel: UploadViewModel) {
val workInfo by viewModel.observeUpload(workId)
.collectAsState(initial = null)
when (workInfo?.state) {
WorkInfo.State.RUNNING -> {
val status = workInfo?.progress?.getString("status") ?: "working"
CircularProgressIndicator()
Text(status)
}
WorkInfo.State.SUCCEEDED -> {
val url = workInfo?.outputData?.getString("url")
Text("Uploaded: $url")
}
WorkInfo.State.FAILED -> Text("Upload failed")
else -> {}
}
}สถานะงานเป็นไปตาม lifecycle: ENQUEUED, RUNNING, SUCCEEDED/FAILED/CANCELLED, BLOCKED (รอ dependencies)
API Work Metrics ของ WorkManager 2.12
WorkManager 2.12.0-rc01 (สิงหาคม 2026) แนะนำ WorkMetricsInfo สำหรับการติดตามประวัติการทำงาน
class MetricsRepository(private val context: Context) {
private val workManager = WorkManager.getInstance(context)
suspend fun getWorkerMetrics(workerName: String): List<WorkMetricsInfo> {
val query = WorkMetricsQuery.Builder()
.setWorkerClassName(workerName)
.setLimit(100)
.build()
return workManager.getWorkMetrics(query)
}
fun analyzeFailures(metrics: List<WorkMetricsInfo>): Map<Int, Int> {
// Count stop reasons
return metrics
.flatMap { it.stopReasonCounts.entries }
.groupBy { it.key }
.mapValues { entry -> entry.value.sumOf { it.value } }
}
}Metrics รวมถึงระยะเวลาการทำงาน, จำนวนการลองใหม่, เหตุผลที่หยุด และ timestamps API นี้ช่วยให้ debug ความล้มเหลวที่ไม่ต่อเนื่องใน production ได้โดยไม่ต้องมีโครงสร้าง logging แบบกำหนดเอง
ข้อมูล WorkMetricsInfo จะถูกลบหลังจาก 7 วันโดยค่าเริ่มต้น กำหนดค่าการเก็บรักษาด้วย Configuration.Builder().setWorkMetricsRetentionDuration()
การทดสอบ Workers ด้วย WorkManagerTestInitHelper
Unit testing workers ต้องการ artifact work-testing TestListenableWorkerBuilder สร้าง workers โดยไม่ต้อง enqueue
@RunWith(AndroidJUnit4::class)
class SyncWorkerTest {
private lateinit var context: Context
@Before
fun setup() {
context = ApplicationProvider.getApplicationContext()
val config = Configuration.Builder()
.setMinimumLoggingLevel(Log.DEBUG)
.setExecutor(SynchronousExecutor())
.build()
WorkManagerTestInitHelper.initializeTestWorkManager(context, config)
}
@Test
fun syncWorker_withValidUserId_succeeds() = runTest {
val inputData = workDataOf("user_id" to "123")
val worker = TestListenableWorkerBuilder<SyncWorker>(context)
.setInputData(inputData)
.build()
val result = worker.doWork()
assertThat(result).isEqualTo(ListenableWorker.Result.success())
}
@Test
fun syncWorker_withoutUserId_fails() = runTest {
val worker = TestListenableWorkerBuilder<SyncWorker>(context)
.build()
val result = worker.doWork()
assertThat(result).isEqualTo(ListenableWorker.Result.failure())
}
}สำหรับ integration tests ที่ตรวจสอบ constraints และ chaining ให้ใช้ TestDriver เพื่อจำลองการตอบสนอง constraint และการผ่านไปของเวลา
คำถามสัมภาษณ์ที่พบบ่อยเกี่ยวกับ WorkManager
การสัมภาษณ์ทางเทคนิคมักทดสอบความเข้าใจเกี่ยวกับการรับประกันและ trade-off ของ WorkManager คำถามเหล่านี้ปรากฏในการสัมภาษณ์ Android ระดับกลางและอาวุโส
ถ: จะเกิดอะไรขึ้นกับ WorkRequest เมื่อแอปถูก kill?
WorkManager จัดเก็บ work requests ในฐานข้อมูล Room เมื่อแอปรีสตาร์ทหรือระบบส่งสัญญาณว่า constraint ได้รับการตอบสนอง งานที่รอดำเนินการจะกลับมาทำงานต่อ การรับประกันนี้ทำให้ WorkManager แตกต่างจากงาน CoroutineScope ที่ตายไปพร้อมกับ process
ถ: WorkManager แตกต่างจาก AlarmManager อย่างไร?
AlarmManager กำหนดเวลา alarm ที่แม่นยำและรันโค้ดในเวลานาฬิกาที่เจาะจง WorkManager กำหนดเวลางานที่สามารถเลื่อนได้ซึ่งรันเมื่อ constraints ตรงตามเงื่อนไข โดยไม่มีการรับประกันเวลาที่แน่นอน ใช้ AlarmManager สำหรับ alarm ที่ผู้ใช้เห็น และ WorkManager สำหรับการประมวลผลข้อมูล background
ถ: WorkManager สามารถรันงานได้ทันทีหรือไม่?
ได้ ด้วย setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) Expedited work requests ใช้ slot foreground service บน API 31+ หรือ JobScheduler.setImportantWhileForeground() บน API ที่เก่ากว่า มีการใช้ข้อจำกัดโควตา ดังนั้น OutOfQuotaPolicy จึงกำหนดพฤติกรรม fallback
ถ: จะยกเลิก pending uploads ทั้งหมดได้อย่างไร?
WorkManager.getInstance(context).cancelAllWorkByTag("upload")Tags เปิดใช้งานการดำเนินการแบบกลุ่ม หรือ cancelUniqueWork("name") ยกเลิก chain ที่เจาะจง
การจัดการ System-Induced Stops ด้วย Backoff Policies
เมื่อระบบหยุด worker (การเพิ่มประสิทธิภาพแบตเตอรี่, แรงกดดันหน่วยความจำ) นโยบาย backoff จะกำหนดเวลา retry
val request = OneTimeWorkRequestBuilder<UploadWorker>()
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
Duration.ofSeconds(30) // Initial delay, minimum 10 seconds
)
.setBackoffOnSystemInterruption(true) // New in 2.11
.build()Exponential backoff เพิ่มความล่าช้าเป็นสองเท่าในแต่ละการลองใหม่: 30s, 60s, 120s สูงสุด 5 ชั่วโมง Linear backoff เพิ่มความล่าช้าเริ่มต้นทุกครั้ง: 30s, 60s, 90s Flag setBackoffOnSystemInterruption() ใหม่ใน WorkManager 2.11 ใช้ backoff แม้ว่าระบบ (ไม่ใช่ worker) เป็นสาเหตุของการหยุด
เริ่มฝึกซ้อมเลย!
ทดสอบความรู้ของคุณด้วยตัวจำลองสัมภาษณ์และแบบทดสอบเทคนิคครับ
ประเด็นสำคัญสำหรับการใช้ WorkManager ใน Production
- เลือกใช้
CoroutineWorkerมากกว่าWorkerเมื่อเรียก suspend functions ซึ่งหลีกเลี่ยงการบล็อก threads และรวมเข้ากับโค้ด coroutine ที่มีอยู่ - ใช้
enqueueUniqueWork()เพื่อป้องกันงานซ้ำ เลือกKEEPสำหรับการดำเนินการ idempotent และREPLACEเมื่อคำขอล่าสุดเท่านั้นที่สำคัญ - ตั้ง tags ที่มีความหมายในทุก request Tags ช่วยให้การสังเกต, การยกเลิก และการ debug ข้าม work chains
- ทดสอบ workers แยกด้วย
TestListenableWorkerBuilderจากนั้นทดสอบ chains ด้วยการจำลอง constraint ของTestDriver - API
WorkMetricsInfoของ WorkManager 2.12 ให้ประวัติการทำงาน ใช้เพื่อ debug รูปแบบ retry และเหตุผลการหยุดใน production - Constraints ช่วยประหยัดแบตเตอรี่ Worker ที่ล้มเหลวเนื่องจากไม่มีเครือข่ายสิ้นเปลือง CPU cycles และใช้พลังงานในการลองใหม่
- ขั้นต่ำ 15 นาทีสำหรับ periodic work ถูกบังคับโดย Android ไม่ใช่ WorkManager ออกแบบงานเป็นระยะให้ทนต่อช่วงเวลานี้
คุณหาบั๊กใน Android เจอไหม
โค้ดจริงหนึ่งชิ้น บั๊กที่ซ่อนอยู่หนึ่งจุด วันละหนึ่งครั้ง ลองได้โดยไม่ต้องมีบัญชี

เขียนโดย
Anthony Fillion-Mailletผู้ก่อตั้ง SharpSkill
เป็นนักพัฒนาฟูลสแตกมากว่า 10 ปี ดูแล SharpSkill และรับผิดชอบทุกสิ่งที่เผยแพร่ที่นี่
อัปเดตเมื่อ 22 สิงหาคม 2569
แชร์
บทความที่เกี่ยวข้อง

การทำ Modularization บน Android ปี 2026: สถาปัตยกรรม Multi-Module และคำถามสัมภาษณ์
เชี่ยวชาญสถาปัตยกรรม multi-module ของ Android ด้วย convention plugins, Gradle version catalogs และ feature modules พร้อมคำถามสัมภาษณ์ที่พบบ่อยเกี่ยวกับกลยุทธ์ modularization

Android CameraX ปี 2026: คู่มือถ่ายภาพและวิดีโอพร้อมคำถามสัมภาษณ์
เรียนรู้ CameraX บน Android 2026: การถ่ายภาพ การบันทึกวิดีโอ การผสานรวม Jetpack Compose และคำถามสัมภาษณ์ทางเทคนิคสำหรับนักพัฒนา Android

Jetpack Navigation Compose 2026: การนำทางแบบ Type-Safe และคำถามสัมภาษณ์งาน
เรียนรู้ Jetpack Navigation Compose 2.10 ที่มีการนำทางแบบ type-safe ด้วย Kotlin Serialization คู่มือฉบับสมบูรณ์พร้อมตัวอย่างโค้ดและคำถามสัมภาษณ์ Android