ภาพรวม
บทความนี้สาธิตวิธีรันโค้ดซ้ำทุก 10 วินาทีใน Android โดยเปรียบเทียบ 3 วิธีหลัก: Handler (Legacy), Kotlin Coroutine (แนะนำ), และ WorkManager (สำหรับ Background Work) พร้อมベスト Practices การจัดการ Lifecycle
ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่
สร้างโปรเจกต์ Android ใหม่ใน Android Studio (แนะนำใช้ Kotlin)
วิธีที่ 1: Handler + Runnable (Java Legacy - โค้ดต้นฉบับ)
Layout (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Handler ทุก 10 วินาที"
android:textSize="18sp" />
</LinearLayout>
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private Handler handler = new Handler(Looper.getMainLooper());
private Runnable runnable;
private final int delay = 10000; // 10 วินาที
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
startPeriodicTask();
}
@Override
protected void onPause() {
super.onPause();
stopPeriodicTask();
}
private void startPeriodicTask() {
runnable = new Runnable() {
@Override
public void run() {
// ทำงานที่นี่ทุก 10 วินาที
Toast.makeText(MainActivity.this, "รันทุก 10 วินาที (Handler)", Toast.LENGTH_SHORT).show();
// Schedule ครั้งถัดไป
handler.postDelayed(this, delay);
}
};
handler.postDelayed(runnable, delay);
}
private void stopPeriodicTask() {
handler.removeCallbacks(runnable);
}
}
วิธีที่ 2: Kotlin Coroutine (แนะนำสำหรับโปรเจกต์ใหม่)
build.gradle (Module: app)
dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.7.0"
}
MainActivity.kt
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import android.os.Bundle
import android.widget.Toast
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// ใช้ lifecycleScope - จะ cancel อัตโนมัติเมื่อ Lifecycle ถูก Destroy
lifecycleScope.launch {
while (true) {
delay(10_000) // 10 วินาที
// ตรวจสอบว่า Activity ยัง Active อยู่
if (isDestroyed || isFinishing) return@launch
runOnUiThread {
Toast.makeText(this@MainActivity, "รันทุก 10 วินาที (Coroutine)", Toast.LENGTH_SHORT).show()
}
}
}
}
}
รูปแบบ Advance: ใช้ flow และ repeatOnLifecycle
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.Lifecycle.State.STARTED
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.collect
lifecycleScope.launch {
repeatOnLifecycle(STARTED) {
flow {
while (true) {
emit(Unit)
delay(10_000)
}
}.collect {
// ทำงานที่นี่ - 運行เฉพาะเมื่อ UI มองเห็น (STARTED)
Toast.makeText(this@MainActivity, "รันทุก 10 วินาที (Flow + Lifecycle)", Toast.LENGTH_SHORT).show()
}
}
}
วิธีที่ 3: WorkManager (สำหรับ Background Periodic Work)
เหมาะสำหรับงานที่ต้องรันแม้แอปจะปิดอยู่ (Sync ข้อมูล, Backup, Upload Log)
build.gradle
dependencies {
implementation "androidx.work:work-runtime-ktx:2.9.0"
}
Worker Class
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import kotlinx.coroutines.delay
class PeriodicWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result = try {
// ทำงาน Background ที่นี่
delay(100) // จำลองงาน
Result.success()
} catch (e: Exception) {
Result.failure()
}
}
การจัดตารางงาน (Schedule)
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import java.util.concurrent.TimeUnit
val workRequest = PeriodicWorkRequestBuilder<PeriodicWorker>(15, TimeUnit.MINUTES)
.setInitialDelay(10, TimeUnit.SECONDS)
.build()
WorkManager.getInstance(context).enqueueUniquePeriodicWork(
"periodic_sync",
ExistingPeriodicWorkPolicy.KEEP,
workRequest
)
หมายเหตุ: WorkManager มีขั้นต่ำ 15 นาที (API 23+) ไม่สามารถตั้ง 10 วินาทีได้ ต้องใช้ Handler/Coroutine แทน
ตารางเปรียบเทียบ
| คุณสมบัติ | Handler | Coroutine + Lifecycle | WorkManager |
|---|---|---|---|
| ความแม่นยำเวลา | ประมาณ (~10 วิ) | แม่นยำมาก | ประมาณ (≥15 นาที) |
| รันเมื่อแอปปิด | ไม่ได้ | ไม่ได้ | ได้ |
| จัดการ Lifecycle | Manual | อัตโนมัติ | อัตโนมัติ |
| Doze Mode | ไม่รองรับ | ไม่รองรับ | รองรับ |
| สำหรับ UI Updates | ได้ | ได้ (แนะนำ) | ไม่ได้ |
ข้อแนะนำ
- UI Periodic Updates: ใช้ Coroutine + repeatOnLifecycle
- Background Sync (แอปปิดได้): ใช้ WorkManager (interval ≥ 15 นาที)
- Legacy Java Project: ใช้ Handler พร้อม removeCallbacks ใน onPause/onDestroy
- ห้ามใช้:
Thread.sleep()บน Main Thread,TimerTask(Leak เงื่อนไข)