Inactive — สถานะเปลี่ยนผ่านในวงจรชีวิตแอปพลิเคชันระหว่าง Active และ Background ซึ่งแอปมองเห็นได้บนหน้าจอแต่ไม่รับเหตุการณ์สัมผัส เราอธิบายว่า Inactive เกิดขึ้นบน iOS และ Android ได้อย่างไร เมธอดตัวแทนใดที่รับผิดชอบ และวิธีจัดการกับการขัดจังหวะ — สายเรียกเข้า การแจ้งเตือน และท่าทางระบบ — อย่างถูกต้อง
ประเด็นสำคัญ
Inactive เป็นสถานะกลางในวงจรชีวิตของแอปมือถือที่เกิดขึ้นระหว่างการเปลี่ยนระหว่าง Active และ Background ในสถานะนี้ แอปยังคงอยู่เบื้องหน้าและมองเห็นได้สำหรับผู้ใช้ แต่ไม่ได้รับเหตุการณ์สัมผัส การกดแป้นพิมพ์ หรือเหตุการณ์ UI อื่น ๆ ระบบจะบล็อกการส่งเหตุการณ์ไปยังแอป แต่ UI ยังคงอยู่บนหน้าจอและไม่ถูกย่อ
ลักษณะของ Inactive เป็นแบบชั่วคราว สถานะนี้กินเวลาเท่ากับระยะเวลาของการขัดจังหวะของระบบ: ตั้งแต่ 0.1 วินาทีเมื่อปิด Control Center อย่างรวดเร็ว ไปจนถึงหลายวินาทีระหว่างสายเรียกเข้าที่มีหน้าจอโทร หลังจากสิ้นสุดการขัดจังหวะ แอปจะกลับไปยัง Active หรือเปลี่ยนไปยัง Background หากผู้ใช้เปลี่ยนไปยังแอปอื่น Inactive เป็นสถานะเดียวที่สามารถเปลี่ยนได้ทั้งสองทิศทาง: กลับไปยัง Active หรือต่อไปยัง Background
บน iOS Inactive ถูกจัดการโดยระบบโดยอัตโนมัติ นักพัฒนาไม่สามารถยืดหรือลดเวลาใน Inactive ได้ — มันถูกควบคุมโดย UIApplication อย่างสมบูรณ์ สิ่งเดียวที่นักพัฒนาสามารถทำได้คือจัดการการเปลี่ยนไปยัง Inactive ผ่าน applicationWillResignActive และการกลับมาผ่าน applicationDidBecomeActive อย่างถูกต้อง บน Android สิ่งที่เทียบเท่าคือ onPause แม้ว่าความหมายจะแตกต่าง: onPause ถูกเรียกแม้ว่า Activity จะถูกปิดบังบางส่วนโดยคอมโพเนนต์อื่น
บน iOS Inactive เป็นสถานะแยกต่างหากในวงจรชีวิตของแอปพลิเคชัน (หนึ่งในห้า: Not Running, Active, Inactive, Background, Suspended) บน Android ไม่มีสิ่งที่เทียบเท่าโดยตรง — onPause ส่งสัญญาณว่า Activity กำลังสูญเสียโฟกัสการป้อนข้อมูลแต่อาจยังคงมองเห็นได้ (ตัวอย่างเช่น เมื่อเปิดไดอะล็อก) ความแตกต่างหลัก: iOS Inactive เป็นสถานะทั่วทั้งแอป ในขณะที่ Android onPause เป็นสถานะต่อ Activity ใน Android มัลติหน้าต่าง Activity หนึ่งสามารถอยู่ใน onPause (ไม่มีโฟกัส) ในขณะที่อีก Activity หนึ่งอยู่ใน onResume (มีโฟกัส)
| คุณลักษณะ | iOS Inactive | Android onPause |
|---|---|---|
| UI มองเห็น | ใช่ | ใช่ (บางส่วนหรือทั้งหมด) |
| เหตุการณ์สัมผัส | ไม่รับ | ไม่รับ |
| ระยะเวลา | จนกว่าการขัดจังหวะจะสิ้นสุด | จนกว่าโฟกัสจะกลับมาหรือไปยังพื้นหลัง |
| สถานะถัดไป | Active หรือ Background | onResume หรือ onStop |
| ระดับ | แอป (UIApplication) | Activity |
| มัลติหน้าต่าง | หนึ่งฉากทำงาน | หลาย Activity ใน onPause |
Inactive บน iOS เกิดขึ้นในหลายสถานการณ์ที่กำหนดไว้อย่างชัดเจน ผู้ใช้เปิด Control Center (ปัดลงจากมุมขวาบนบน iPhone X+ หรือปัดขึ้นบนรุ่นเก่า) ผู้ใช้เปิด Notification Center (ปัดลงจากมุมซ้ายบน) สายเรียกเข้าเข้ามา — ระบบแสดงหน้าจอโทรเหนือแอป มีการขอสิทธิ์ระบบ — ตำแหน่งที่ตั้ง ไมโครโฟน กล้อง รายชื่อติดต่อ บน iPad เปิด Slide Over หรือ Split View — ฉากที่ทำงานอยู่กลายเป็น Inactive
บน Android onPause (สิ่งที่เทียบเท่าของ Inactive) เกิดขึ้นในช่วงสถานการณ์ที่กว้างยิ่งขึ้น การเปิดไดอะล็อก (AlertDialog, DialogFragment) การซ้อนทับบางส่วนของ Activity โดย Activity อื่น (ตัวอย่างเช่น Activity โปร่งใสสำหรับการยืนยันตัวตน) การหมุนหน้าจอ (Activity ถูกสร้างใหม่ ลำดับ: onPause → onStop → onDestroy → onCreate → onStart → onResume) โหมดมัลติหน้าต่าง — หน้าต่างที่ไม่ทำงานได้รับ onPause แต่ละเหตุการณ์เหล่านี้ต้องการการระงับการดำเนินงานที่ใช้ทรัพยากรมาก เพื่อรักษาแบตเตอรี่และประสิทธิภาพ
import UIKit
extension Notification.Name {
static let systemInterruptionBegan = Notification.Name("systemInterruptionBegan")
static let systemInterruptionEnded = Notification.Name("systemInterruptionEnded")
}
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillResignActive(_ application: UIApplication) {
// แอปเปลี่ยนไปยัง Inactive — การขัดจังหวะของระบบ
print("การขัดจังหวะ: Control Center, สายเรียกเข้า หรือการแจ้งเตือนระบบ")
// ระงับการดำเนินงานที่ไวต่อเวลา
pauseVideoPlayback()
stopContinuousDataCollection()
hideSensitiveInformation()
// แจ้งคอมโพเนนต์
NotificationCenter.default.post(name: .systemInterruptionBegan, object: nil)
}
// กลับจาก Inactive ไปยัง Active
func applicationDidBecomeActive(_ application: UIApplication) {
resumeVideoPlayback()
restartDataCollection()
NotificationCenter.default.post(name: .systemInterruptionEnded, object: nil)
}
private func pauseVideoPlayback() {
// หยุดวิดีโอชั่วคราวเพื่อไม่ให้เสียงซ้อนทับ
}
private func hideSensitiveInformation() {
// ซ่อนข้อมูลที่ละเอียดอ่อนเมื่อจับภาพหน้าจอ
// Control Center/App Switcher จับภาพหน้าจอ UI
}
}โค้ดแสดงการจัดการ Inactive ใน UIKit applicationWillResignActive หยุดวิดีโอชั่วคราว หยุดการรวบรวมข้อมูล และซ่อนข้อมูลที่ละเอียดอ่อน สิ่งนี้สำคัญเพราะเมื่อเปิด Control Center หรือ App Switcher ระบบจะจับภาพหน้าจอของ UI ปัจจุบัน — ผู้ใช้อาจเห็นข้อมูลที่เป็นความลับในตัวอย่างภาพ NotificationCenter อนุญาตให้คอมโพเนนต์ของแอปสมัครรับเหตุการณ์การขัดจังหวะ
บน iOS Inactive ถูกจัดการโดยเมธอดคู่หนึ่ง: applicationWillResignActive (การเปลี่ยนไปยัง Inactive) และ applicationDidBecomeActive (การกลับมาจาก Inactive) เมธอดเหล่านี้เป็นส่วนหนึ่งของ UIApplicationDelegate และถูกเรียกสำหรับทุกการเปลี่ยนผ่าน Inactive ตั้งแต่ iOS 13 และ UISceneDelegate ได้เพิ่ม sceneWillResignActive และ sceneDidBecomeActive สำหรับสถานการณ์มัลติหน้าต่าง
บน iPad ที่ใช้ iOS 13+ แอปสามารถมีหลายฉาก (หน้าต่าง) แต่ละฉากมีวงจรชีวิตของตัวเอง ฉากหนึ่งสามารถกลายเป็น Inactive (ผู้ใช้เปลี่ยนไปยังฉากอื่น) ในขณะที่อีกฉากหนึ่งยังคง Active นี่คือความแตกต่างที่สำคัญจาก iPhone ที่ Inactive เป็นสถานะทั่วโลกสำหรับทั้งแอป เมื่อพัฒนาสำหรับ iPad คุณต้องจัดการ Inactive สำหรับแต่ละฉากแยกกัน
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// ฉากกลายเป็นไม่ทำงาน
func sceneWillResignActive(_ scene: UIScene) {
// บน iPad ฉากนี้สูญเสียโฟกัส แต่ฉากอื่นอาจยังทำงานอยู่
print("ฉากสูญเสียการทำงาน")
// ระงับงานของฉากนี้
pauseSceneSpecificOperations()
}
// ฉากกลายเป็นทำงาน
func sceneDidBecomeActive(_ scene: UIScene) {
print("ฉากกลายเป็นทำงานแล้ว")
resumeSceneSpecificOperations()
}
private func pauseSceneSpecificOperations() {
// ระงับการดำเนินงานเฉพาะของฉากนี้
}
private func resumeSceneSpecificOperations() {
// เริ่มการดำเนินงานใหม่เมื่อโฟกัสกลับมา
}
}
// AppDelegate ยังคงเป็นจุดเริ่มต้น มอบหมายให้ฉาก
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role
)
}
}โค้ดแสดง SceneDelegate สำหรับจัดการ Inactive ในระดับฉาก sceneWillResignActive ถูกเรียกเมื่อหน้าต่างเฉพาะสูญเสียโฟกัส — สิ่งนี้สามารถเกิดขึ้นเมื่อสลับระหว่างหน้าต่างบน iPad AppDelegate กำหนดค่า UISceneConfiguration เพื่อรองรับมัลติหน้าต่าง แต่ละฉากมีสถานะอิสระและนักพัฒนาต้องจัดการแยกกัน
บน Android สิ่งที่เทียบเท่าโดยตรงของ iOS Inactive คือเมธอด onPause() ของวงจรชีวิต Activity มันถูกเรียกเมื่อ Activity สูญเสียโฟกัสการป้อนข้อมูลแต่อาจยังคงมองเห็นได้ สถานการณ์ทั่วไป: การเปิดไดอะล็อก การเริ่ม Activity อื่นในแอปเดียวกัน สายเรียกเข้า การกดปุ่ม Home หรือ Recents ใน onPause นักพัฒนาควรระงับการดำเนินงานที่ใช้ทรัพยากรมาก — อนิเมชัน การเล่นวิดีโอ การทำงานกับกล้อง
ความแตกต่างที่สำคัญของ Android คือ onPause มาก่อน onStop เสมอ แต่ไม่ใช่ในทางกลับกัน Activity สามารถรับ onPause โดยไม่มี onStop (ตัวอย่างเช่น เมื่อเปิด Activity โปร่งใส) นอกจากนี้ onPause สามารถถูกเรียกหลายครั้งในช่วงอายุของ Activity — ในการสลับโฟกัสแต่ละครั้ง อย่าวางลอจิกครั้งเดียวใน onPause — ใช้ onStop สำหรับการดำเนินงานสุดท้ายและ onPause สำหรับการระงับการกระทำเชิงโต้ตอบเท่านั้น
class VideoPlayerActivity : AppCompatActivity() {
private var exoPlayer: ExoPlayer? = null
private var currentPosition: Long = 0L
override fun onPause() {
super.onPause()
// แอปสูญเสียโฟกัส — หยุดวิดีโอชั่วคราว
exoPlayer?.let { player ->
if (player.isPlaying) {
currentPosition = player.currentPosition
player.pause()
}
}
// ซ่อนข้อมูลที่ละเอียดอ่อน (GDPR/หน้าจอธนาคาร)
if (window.decorView.systemUiVisibility and
View.SYSTEM_UI_FLAG_SECURE == 0
) {
hideSensitiveOverlay()
}
}
override fun onResume() {
super.onResume()
// โฟกัสกลับมา — เริ่มการเล่นใหม่
exoPlayer?.seekTo(currentPosition)
exoPlayer?.play()
showSensitiveOverlay()
}
private fun hideSensitiveOverlay() {
// วางหน้าจอสีดำทับข้อมูลทางการเงิน
}
}โค้ดแสดงการจัดการ onPause ที่ถูกต้องสำหรับเครื่องเล่นวิดีโอ ExoPlayer ถูกหยุดชั่วคราวเมื่อสูญเสียโฟกัส และตำแหน่งการเล่นถูกบันทึก เมื่อกลับไปยัง onResume เครื่องเล่นจะเล่นต่อจากตำแหน่งที่บันทึกไว้ นอกจากนี้ยังแสดงรูปแบบการซ่อนข้อมูลที่ละเอียดอ่อน — สำคัญสำหรับแอปทางการเงินและการแพทย์ที่ต้องการการปกป้องจากภาพหน้าจอเมื่อสลับแอป
กฎข้อแรก — ซ่อนข้อมูลที่เป็นความลับเมื่อเปลี่ยนไปยัง Inactive เมื่อผู้ใช้เปิด Control Center หรือ App Switcher iOS จะจับภาพหน้าจอปัจจุบัน บน Android เช่นเดียวกัน ระบบจะแสดงตัวอย่างของ Activity ล่าสุดใน Recents ใช้ UIApplication.shouldSnapshotSecureApp (iOS 16+) หรือ FLAG_SECURE (Android) เพื่อป้องกันหน้าจอที่เป็นความลับ
กฎข้อที่สอง — หยุดอนิเมชันและสื่อชั่วคราว Inactive ไม่ใช่เวลาที่ดีสำหรับการเล่นวิดีโอหรืออนิเมชัน เพราะผู้ใช้ไม่สามารถมองเห็นได้ นอกจากนี้ การเล่นในพื้นหลังอาจทำให้เสียงซ้อนทับกับเสียงระบบ (เสียงเรียกเข้า การแจ้งเตือน) หยุด AVPlayer, ExoPlayer และ UIView.animateเมื่อไปยัง Inactive และเริ่มใหม่เมื่อกลับไปยัง Active
กฎข้อที่สาม — บล็อกการป้อนข้อมูล หากแอปมีฟอร์มป้อนข้อมูลหรือร่างเอกสาร ให้ล็อกแป้นพิมพ์และฟิลด์ป้อนข้อมูลเมื่อไปยัง Inactive สิ่งนี้ป้องกันการป้อนข้อมูลโดยไม่ตั้งใจเมื่อกลับมาและป้องกันการสกัดกั้นข้อมูลผ่านการซ้อนทับของระบบ บน iOS ให้ปลดผู้ตอบสนองคนแรก (view.endEditing(true)), บน Android — ล้างโฟกัส (currentFocus?.clearFocus())
กฎข้อที่สี่ — อย่าดำเนินงานที่ยาวนานใน applicationWillResignActive หรือ onPause เมธอดเหล่านี้ควรเสร็จสิ้นในเสี้ยววินาที หากคุณต้องการบันทึกข้อมูลจำนวนมาก ให้เริ่มบันทึกในเธรดพื้นหลังและทำให้เสร็จใน applicationDidEnterBackground หรือ onStop iOS ให้ 5 วินาทีสำหรับการดำเนินการ applicationWillResignActive หลังจากนั้นระบบอาจบังคับปิดแอป
import UIKit
final class SecureOverlayManager {
private var blurView: UIVisualEffectView?
func showBlurOverlay() {
guard let window = UIApplication.shared.keyWindow,
blurView == nil
else { return }
let blur = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
blur.frame = window.bounds
blur.autoresizingMask = [.flexibleWidth, .flexibleHeight]
window.addSubview(blur)
blurView = blur
}
func removeBlurOverlay() {
blurView?.removeFromSuperview()
blurView = nil
}
}
// การใช้งานใน AppDelegate
func applicationWillResignActive(_ application: UIApplication) {
SecureOverlayManager().showBlurOverlay()
}
func applicationDidBecomeActive(_ application: UIApplication) {
SecureOverlayManager().removeBlurOverlay()
}โค้ดแสดงการใช้งานการซ้อนทับที่ปลอดภัยสำหรับการปกป้องข้อมูลระหว่างการเปลี่ยนไปยัง Inactive UIVisualEffectView ที่มีเอฟเฟกต์เบลอถูกวางซ้อนบน UI ทั้งหมดเมื่อไปยัง Inactive และถูกลบออกเมื่อกลับไปยัง Active สิ่งนี้รับประกันว่าข้อมูลที่เป็นความลับจะไม่ปรากฏในภาพหน้าจอของ App Switcher และ Control Center เช่นเดียวกัน คุณสามารถใช้ UIImageView พร้อมโลโก้สำหรับการซ้อนทับที่มีตราสินค้า
คำถามที่พบบ่อย
ใช่ Inactive เป็นสถานะกลางที่จำเป็นก่อนการเปลี่ยนไปยัง Background บน iOS แอปไม่สามารถไปจาก Active ตรงไปยัง Background ได้ — มันจะกลายเป็น Inactive ก่อน จากนั้นจึง Background บน Android เช่นเดียวกัน onPause ถูกเรียกก่อน onStop เสมอ สิ่งนี้เปิดโอกาสให้นักพัฒนาเตรียมข้อมูลสำหรับบันทึกก่อนที่จะไปยังพื้นหลังอย่างสมบูรณ์
ใช่ บน iPad เมื่อเปิด Slide Over หรือ Split View ฉากที่ทำงานอยู่จะกลายเป็น Inactive แม้ว่าจะไม่มีการขัดจังหวะของระบบเกิดขึ้น — ผู้ใช้เพียงแค่โต้ตอบกับอีกฉากหนึ่ง นี่คือคุณสมบัติของ iPadOS แบบมัลติหน้าต่าง บน iPhone Inactive ถูกกระตุ้นโดยการขัดจังหวะของระบบเสมอ — สายเรียกเข้า การแจ้งเตือน Control Center หรือ Notification Center
โดยปกติตั้งแต่ 0.1 ถึง 2 วินาที ระหว่างสายเรียกเข้าที่มีหน้าจอโทร — สูงสุด 30 วินาที (จนกว่าผู้ใช้จะรับหรือปฏิเสธสาย) iOS ไม่จำกัดเวลาใน Inactive อย่างบังคับ แต่ระบบอาจปิดแอปหากไม่ตอบสนองต่อเหตุการณ์ (watchdog) บน Android onPause ไม่มีข้อจำกัดด้านเวลา แต่แนะนำให้ทำงานเสร็จภายใน 200 ms
ScenePhase.inactive — ค่า enum ScenePhase ที่ตั้งค่าเมื่อฉากอยู่เบื้องหน้าแต่ไม่ได้รับเหตุการณ์ ใน SwiftUI คุณสามารถสังเกตมันผ่าน @Environment(\.scenePhase) และตอบสนองผ่าน onChange เมื่อเปลี่ยนจาก .active เป็น .inactive ให้หยุดตัวจับเวลาและอนิเมชันชั่วคราว เมื่อกลับไปยัง .active ให้เริ่มใหม่ เมื่อไปยัง .background ให้บันทึกสถานะ
ไม่ สำหรับแอปที่จัดการข้อมูลที่เป็นความลับเท่านั้น: ธนาคาร การแพทย์ องค์กร และแอปส่งข้อความที่มีแชทส่วนตัว สำหรับเกมและแอปบันเทิง ไม่จำเป็นต้องซ่อน UI อย่างไรก็ตาม การหยุดเกมเพลย์และเสียงระหว่าง Inactive เป็นแนวทางปฏิบัติที่ดีเพื่อหลีกเลี่ยงการซ้อนทับของเสียงกับการแจ้งเตือนระบบ Apple แนะนำให้ซ่อนข้อมูลที่ละเอียดอ่อนแต่ไม่ได้บังคับ
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ