onResume เป็นเมธอดของวงจรชีวิต Android ที่ถูกเรียกเมื่อ Activity หรือ Fragment มาอยู่เบื้องหน้าและได้รับโฟกัสอินพุต ในสถานะนี้ หน้าจอพร้อมสำหรับการโต้ตอบกับผู้ใช้: อีเวนต์สัมผัส การกดปุ่ม และท่าทางทั้งหมดจะถูกส่งไปยังคอมโพเนนต์นี้ onResume เป็นสถานะการทำงานของ Activity ซึ่งแอปพลิเคชันใช้เวลาส่วนใหญ่ไปกับมัน ที่นี่คือที่ที่คุณเปิดกล้อง เริ่มเล่นวิดีโอ เริ่มการรู้จำเสียง และลงทะเบียน ตัวฟังเซนเซอร์ ที่ต้องการการเข้าถึงแบบเอกสิทธิ์ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวงจรชีวิต Activity อย่างสมบูรณ์ โปรดอ่านบทความ Activity Lifecycle
ประเด็นสำคัญ
onResume — เมธอดที่สามของวงจรชีวิต Activity ถูกเรียกหลังจาก onStart ซึ่งส่งสัญญาณว่าหน้าจอพร้อมสำหรับการโต้ตอบกับผู้ใช้อย่างเต็มรูปแบบ ในขณะนี้ Activity อยู่ที่ด้านบนสุดของสแต็กงาน (back stack) ระบบจะส่งอีเวนต์อินพุตทั้งหมดไปยังมัน และแอปพลิเคชันสามารถเริ่มการดำเนินการใดๆ ที่ต้องการการมีส่วนร่วมอย่าง active ของผู้ใช้: การโทรวิดีโอ เกม การบันทึกเสียง การวาดบน Canvas
onResume เป็นส่วนหนึ่งของ “ช่วงชีวิตเบื้องหน้า” (foreground lifetime) — ช่วงเวลาระหว่าง onResume และ onPause นี่คือช่วงเวลาที่แอคทีฟที่สุดของ Activity เมื่อแอปพลิเคชันใช้ทรัพยากรมากที่สุด: CPU สำหรับการประมวลผลสัมผัส GPU สำหรับการเรนเดอร์แอนิเมชัน กล้องและไมโครโฟนสำหรับการจับภาพวิดีโอ การทำความเข้าใจระดับวงจรชีวิตนี้มีความสำคัญอย่างยิ่งสำหรับการเพิ่มประสิทธิภาพการใช้พลังงาน — ทรัพยากรที่เปิดใน onResume ต้องปิดทันทีใน onPause
ตามข้อมูลของ Google I/O 2025 เวลาเฉลี่ยที่ Activity ใช้ในสถานะ onResume ต่อหนึ่งเซสชันคือ 2–5 นาทีสำหรับแอปพลิเคชันข่าว และ 15–30 นาทีสำหรับเกมและแอปส่งข้อความ เวลาที่เหลือทั้งหมด Activity อยู่ในสถานะ onPause, onStop หรือ onDestroy ซึ่งหมายความว่าการเพิ่มประสิทธิภาพโค้ด onResume โดยเฉพาะให้ผลประโยชน์สูงสุดในด้านประสิทธิภาพและอายุการใช้งานแบตเตอรี่
ใน Activity เมธอด onResume ถูกเรียกทุกครั้งที่หน้าจอได้รับโฟกัสอินพุต — เมื่อเริ่มต้นครั้งแรก เมื่อกลับจาก Activity อื่น เมื่อปิดไดอะล็อก เมื่อปลดล็อกอุปกรณ์ นี่คือเมธอด “ร้อน” ที่สามารถถูกเรียกได้หลายครั้งต่อเซสชัน และการใช้งานควรเบาที่สุดเท่าที่เป็นไปได้
class CameraActivity : AppCompatActivity() {
private var cameraProvider: ProcessCameraProvider? = null
private var preview: Preview? = null
override fun onResume() {
super.onResume()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
cameraProvider = cameraProviderFuture.get()
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
preview = Preview.Builder().build().also {
it.setSurfaceProvider(binding?.viewFinder?.surfaceProvider)
}
try {
cameraProvider?.unbindAll()
cameraProvider?.bindToLifecycle(
this, cameraSelector, preview
)
} catch (e: Exception) {
Log.e("Camera", "Failed to bind camera", e)
}
}, ContextCompact.getMainExecutor(this))
}
override fun onPause() {
super.onPause()
cameraProvider?.unbindAll()
preview = null
}
}
ตัวอย่าง CameraX แสดงให้เห็นการใช้งานคลาสสิกของ onResume/onPause: กล้องเป็นทรัพยากรเอกสิทธิ์ที่แอปพลิเคชันเดียวเท่านั้นที่สามารถใช้ได้ในแต่ละครั้ง การผูกกล้องกับวงจรชีวิตผ่าน bindToLifecycle จะปิดกล้องโดยอัตโนมัติใน onPause แต่การเรียก unbindAll อย่างชัดแจ้งรับประกันการปล่อยทันที สิ่งนี้สำคัญโดยเฉพาะเมื่อสลับระหว่าง Activities: กล้องต้องถูกปล่อยก่อนที่ Activity อื่นจะพยายามเปิดมัน
onResume ใน Fragment ถูกเรียกหลังจาก Activity ที่บรรจุมันได้รับ onResume อย่างไรก็ตาม เนื่องจากคุณสมบัติเฉพาะของ FragmentManager และ ViewPager ช่วงเวลาของการเรียก onResume สำหรับ Fragment อาจล่าช้าเมื่อเทียบกับ Activity ตัวอย่างเช่น Fragment ใน ViewPager ที่มี offscreenPageLimit = 1 จะได้รับ onResume เฉพาะเมื่อมันกลายเป็นหน้าปัจจุบัน ไม่ใช่เมื่อ Activity เริ่มต้น
class VideoPlayerFragment : Fragment() {
private var exoPlayer: ExoPlayer? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
exoPlayer = ExoPlayer.Builder(requireContext()).build()
binding?.playerView?.player = exoPlayer
}
override fun onResume() {
super.onResume()
exoPlayer?.play()
if (userVisibleHint) {
startBiometricAuth()
}
}
override fun onPause() {
exoPlayer?.pause()
stopBiometricAuth()
super.onPause()
}
}
การตรวจสอบ userVisibleHint ใน Fragment.onResume เกี่ยวข้องกับ ViewPager: Fragment อาจได้รับ onResume แต่ถูกซ่อนโดยหน้าที่อยู่ติดกัน (เช่น ระหว่างการเปลี่ยนภาพแบบเคลื่อนไหว) ในกรณีเช่นนี้ การเริ่มวิดีโอหรือไบโอเมตริกใน onResume โดยไม่ตรวจสอบการมองเห็นจะนำไปสู่พฤติกรรมที่ไม่คาดคิด ตั้งแต่ Fragment 1.5.0 เป็นต้นไป แนะนำให้ใช้ FragmentTransaction.setMaxLifecycle() สำหรับการควบคุมวงจรชีวิตของ fragment ใน ViewPager2 อย่างแม่นยำ
นักพัฒนามักสับสนระหว่าง onStart และ onResume โดยวางโค้ดในเมธอดที่ผิด กฎหลัก: onStart — สำหรับทรัพยากรที่ทำงานระหว่างการมองเห็น; onResume — สำหรับทรัพยากรที่ต้องการโฟกัสอินพุต มาดูสถานการณ์เฉพาะและการเลือกเมธอดที่ถูกต้องกัน
| การดำเนินการ | เมธอด | เหตุผล |
|---|---|---|
| การสมัครสมาชิกตำแหน่งทางภูมิศาสตร์ | onStart / onStop | GPS สามารถทำงานได้เมื่อมองเห็นบางส่วน |
| การเปิดกล้อง | onResume / onPause | กล้องเป็นทรัพยากรเอกสิทธิ์ |
| BroadcastReceiver | onStart / onStop | อีเวนต์ระบบไม่ต้องการโฟกัส |
| การเล่นวิดีโอ | onResume / onPause | วิดีโอต้องมองเห็นได้สำหรับผู้ใช้ |
| การสแกน Bluetooth | onStart / onStop | การสแกนสามารถทำงานในพื้นหลังได้ |
| เครื่องบันทึกเสียง (MediaRecorder) | onResume / onPause | การบันทึกต้องการ UI ที่ active |
| ตัวฟังเซนเซอร์ | onResume / onPause | เซนเซอร์สำหรับเกมและท่าทาง |
| การอัปเดตข้อมูล | onStart | ต้องการข้อมูลล่าสุดเมื่อปรากฏ |
กฎปฏิบัติ: หากการดำเนินการควรถูกขัดจังหวะเมื่อไดอะล็อกปรากฏขึ้น — ใช้ onResume/onPause หากการดำเนินการสามารถดำเนินต่อไปเมื่อหน้าจอถูกปิดบางส่วน — ใช้ onStart/onStop ตัวอย่างเช่น เครื่องเล่นวิดีโอควรหยุดวิดีโอชั่วคราวเมื่อเปิดไดอะล็อก (onPause) ในขณะที่ตำแหน่งทางภูมิศาสตร์สามารถอัปเดตต่อไปได้ (ยังคงอยู่ใน onStart)
ทรัพยากรเอกสิทธิ์คือคอมโพเนนต์ของอุปกรณ์ที่แอปพลิเคชันเดียวเท่านั้นสามารถใช้ได้ในเวลาที่กำหนด กล้อง ไมโครโฟน เอาต์พุตวิดีโอ (MediaProjection) อะแดปเตอร์ NFC ในโหมดอ่าน อุปกรณ์ USB ในโหมดอุปกรณ์เสริม — ทรัพยากรทั้งหมดนี้ต้องเปิดใน onResume และปล่อยใน onPause
MediaRecorder ใช้สำหรับบันทึกเสียงและวิดีโอ การขอสิทธิ์และการเตรียม MediaRecorder ทำใน onCreate ในขณะที่การเริ่มบันทึกใน onResume หากผู้ใช้สลับไปยังแอปพลิเคชันอื่น onPause จะหยุดการบันทึกชั่วคราวและ onResume จะเริ่มต่อ นี่คือพฤติกรรมมาตรฐานสำหรับเครื่องบันทึกเสียงและแอปพลิเคชันบันทึกวิดีโอ
private var mediaRecorder: MediaRecorder? = null
private var isRecording = false
override fun onResume() {
super.onResume()
if (isRecording) {
mediaRecorder?.resume()
}
}
override fun onPause() {
if (isRecording) {
mediaRecorder?.pause()
}
super.onPause()
}
การตรวจสอบสิทธิ์ไบโอเมตริก (BiometricPrompt) ควรเรียกเฉพาะเมื่อ Activity อยู่ใน onResume หากเรียกใน onCreate หรือ onStart ไดอะล็อกไบโอเมตริกอาจปรากฏขึ้นก่อนที่ Activity จะเสร็จสิ้นการเริ่มต้น ส่งผลให้การประมวลผลผลลัพธ์ไม่ถูกต้อง การเรียกใน onResume รับประกันว่าหน้าต่างไบโอเมตริกจะแสดงในบริบทที่ถูกต้อง
มาดูรูปแบบที่พิสูจน์แล้วสามรูปแบบสำหรับการทำงานกับ onResume ที่ใช้ในโครงการเชิงพาณิชย์: การรีเซ็ตตัวจับเวลาไม่มีการเคลื่อนไหว การอัปเดตข้อมูลที่มองเห็น และการรวมเข้ากับ Jetpack Navigation
ในแอปพลิเคชันที่มีข้อมูลที่ละเอียดอ่อน (ธนาคาร เวชระเบียน) onResume ใช้สำหรับรีเซ็ตตัวจับเวลาการออกจากระบบอัตโนมัติ หากผู้ใช้กำลังโต้ตอบกับแอปพลิเคชันอย่าง active onResume จะถูกเรียกทุกครั้งที่มีการเปลี่ยนหน้าจอและตัวจับเวลาจะรีเซ็ต หากผู้ใช้ย่อแอปพลิเคชัน onPause จะหยุดตัวจับเวลา และ onResume เมื่อกลับมาจะรีเซ็ตหรือขอการตรวจสอบสิทธิ์อีกครั้ง
รายการที่ต้องแสดงข้อมูลล่าสุดทุกครั้งที่กลับมาที่หน้าจอจะถูกอัปเดตใน onResume ตัวอย่างเช่น หากผู้ใช้สร้างรายการใหม่ใน Activity อื่นและนำทางกลับมา onResume จะโหลดรายการใหม่จากฐานข้อมูลภายในหรือแคช ViewModel สิ่งนี้รับประกันความสอดคล้องของข้อมูลโดยไม่ต้องเรียก notifyDataSetChanged ด้วยตนเอง
override fun onResume() {
super.onResume()
// ActivityResultLauncher ส่งคืนผลลัพธ์ — กำลังอัปเดตรายการ
viewModel.refreshList()
// รีเซ็ตตัวจับเวลาไม่มีการเคลื่อนไหว
inactivityTimer.reset()
}
ใน Jetpack Navigation onResume ของ fragment จะถูกเรียกทุกครั้งที่คุณกลับมายัง fragment นั้นผ่านการนำทางย้อนกลับ คุณสมบัตินี้ใช้สำหรับรีเซ็ตสถานะ UI: ซ่อนคีย์บอร์ด ล้างฟิลด์ค้นหา อัปเดตชื่อแถบเครื่องมือ OnBackPressedCallback ร่วมกับ onResume ให้การควบคุมการนำทางอย่างสมบูรณ์โดยไม่ต้องทำซ้ำโค้ด
คำถามที่พบบ่อย
onStart — หน้าจอมองเห็นได้ onResume — หน้าจอ active และพร้อมสำหรับการโต้ตอบ ลองนึกภาพ: คุณกำลังดูทีวี (onStart) แต่คุณหยิบรีโมทคอนโทรล (onResume) ทีวีมองเห็นได้เสมอ แต่การโต้ตอบเริ่มต้นด้วยรีโมทเท่านั้น ถ้าใครบางคนปิดทีวีด้วยม่าน — หน้าจอจะไม่สามารถมองเห็นได้อีกต่อไป (onStop) ถ้าใครบางคนเอารีโมทไปจากคุณ — การโต้ตอบหยุดลง (onPause) แต่ทีวียังคงมองเห็นได้
onResume ถูกเรียก ทุกครั้งที่ Activity ได้รับโฟกัสอินพุต ขั้นต่ำคือหนึ่งครั้ง (เมื่อเริ่มต้น) สูงสุดขึ้นอยู่กับสถานการณ์การใช้งาน: การสลับระหว่างหน้าจอ การเปิดไดอะล็อก การล็อกและปลดล็อกอุปกรณ์อย่างรวดเร็ว — แต่ละสถานการณ์ดังกล่าวเรียก onResume เมื่อกลับมาที่หน้าจอ
กล้องเป็น ทรัพยากรเอกสิทธิ์ที่พร้อมใช้งานสำหรับแอปพลิเคชันเดียวในแต่ละครั้ง หากคุณเปิดกล้องใน onCreate หรือ onStart กล้องจะถูกล็อกสำหรับแอปพลิเคชันอื่นแม้ว่าแอปพลิเคชันของคุณจะไม่ทำงาน onResume รับประกันว่ากล้องจะเปิดเฉพาะเมื่อ Activity อยู่เบื้องหน้า และ onPause จะปิดมันทันที นี่คือมาตรฐานการพัฒนา Android ที่กำหนดไว้ในเอกสาร CameraX และ Camera2 API
ใช่ onResume อาจไม่เกิดขึ้นหาก Activity ถูกทับโดย Activity อื่นทันทีหลังจากปรากฏ ตัวอย่างเช่น Activity A เริ่ม Activity B ในเมธอด onCreate หรือ onStart ในกรณีนี้ A ได้รับ onStart → onPause → onStop โดยข้าม onResume ระบบไม่เรียก onResume เพราะ Activity A ไม่เคยได้รับโฟกัสอินพุต
ใน onResume ไม่ควรดำเนินการแบบซิงโครนัสที่ยาวนาน: โหลดข้อมูลขนาดใหญ่จากเครือข่าย คำสั่ง SQL ที่ซับซ้อน การประมวลผลภาพ onResume ทำงานในเธรด UI และการบล็อกใดๆ ที่นานกว่า 100–200 มิลลิวินาทีทำให้เกิดความล่าช้าในการตอบสนองอินเทอร์เฟซ การดำเนินการหนักทั้งหมดควรเป็นแบบอะซิงโครนัส — ผ่าน coroutines, RxJava หรือ WorkManager นอกจากนี้ ไม่แนะนำให้เรียก finish() ใน onResume โดยไม่ตรวจสอบ — สิ่งนี้อาจนำไปสู่การลูปสร้างใหม่ไม่รู้จบ
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ