Inactive — trạng thái chuyển tiếp giữa Active và Background

Tác giả: IT Sectr Đã đăng: 2026-03-03 Thời gian đọc: 10 phút

Inactive — trạng thái chuyển tiếp trong vòng đời ứng dụng giữa Active và Background, trong đó ứng dụng hiển thị trên màn hình nhưng không nhận được sự kiện chạm. Chúng tôi giải thích cách Inactive xảy ra trên iOS và Android, phương thức delegate nào xử lý nó và cách xử lý chính xác các gián đoạn — cuộc gọi, thông báo và cử chỉ hệ thống.

Những điểm chính

  • Inactive — ứng dụng hiển thị trên màn hình nhưng không nhận sự kiện chạm do gián đoạn hệ thống
  • applicationWillResignActive — phương thức chính báo hiệu chuyển tiếp sang Inactive trên iOS
  • Tính chất tạm thời — Inactive kéo dài từ phần nhỏ của giây đến vài giây, sau đó chuyển sang Active hoặc Background
  • Nguyên nhân — cuộc gọi đến, Control Center, Notification Center, cảnh báo hệ thống, Apple Pay, Siri
  • SwiftUI — scenePhase .inactive tương đương với Inactive trong UIKit

Inactive — bản chất của trạng thái chuyển tiếp

Inactive là trạng thái trung gian trong vòng đời ứng dụng di động xảy ra trong quá trình chuyển tiếp giữa Active và Background. Ở trạng thái này, ứng dụng vẫn ở tiền cảnh và hiển thị cho người dùng, nhưng không nhận được sự kiện chạm, nhấn phím hoặc các sự kiện UI khác. Hệ thống chặn việc phân phối sự kiện đến ứng dụng, nhưng UI vẫn ở trên màn hình và không bị thu nhỏ.

Bản chất của Inactive là tạm thời. Trạng thái này kéo dài chính xác bằng thời gian gián đoạn hệ thống: từ 0,1 giây khi đóng nhanh Control Center đến vài giây trong cuộc gọi đến có màn hình cuộc gọi. Sau khi gián đoạn kết thúc, ứng dụng trở về Active hoặc chuyển sang Background nếu người dùng đã chuyển sang ứng dụng khác. Inactive là trạng thái duy nhất có thể chuyển tiếp theo cả hai hướng: quay lại Active hoặc tiếp tục sang Background.

Trên iOS, Inactive được quản lý tự động bởi hệ thống. Nhà phát triển không thể kéo dài hay rút ngắn thời gian ở Inactive — nó hoàn toàn được kiểm soát bởi UIApplication. Điều duy nhất nhà phát triển có thể làm là xử lý chính xác việc chuyển sang Inactive qua applicationWillResignActive và quay lại qua applicationDidBecomeActive. Trên Android, tương đương là onPause, mặc dù ngữ nghĩa khác nhau: onPause được gọi ngay cả khi một Activity bị che phủ một phần bởi thành phần khác.

So sánh Inactive trên iOS và Android

Trên iOS, Inactive là một trạng thái riêng biệt trong vòng đời ứng dụng (một trong năm: Not Running, Active, Inactive, Background, Suspended). Trên Android không có tương đương trực tiếp — onPause báo hiệu rằng Activity đang mất tiêu điểm đầu vào nhưng có thể vẫn hiển thị (ví dụ: khi mở hộp thoại). Sự khác biệt chính: Inactive trên iOS là trạng thái toàn ứng dụng, trong khi onPause trên Android là trạng thái trên mỗi Activity. Trong đa cửa sổ Android, một Activity có thể ở onPause (không có tiêu điểm) trong khi Activity khác ở onResume (có tiêu điểm).

Đặc điểmiOS InactiveAndroid onPause
UI hiển thịCó (một phần hoặc toàn bộ)
Sự kiện chạmKhông nhậnKhông nhận
Thời gianCho đến khi gián đoạn kết thúcCho đến khi tiêu điểm quay lại hoặc vào nền
Trạng thái tiếp theoActive hoặc BackgroundonResume hoặc onStop
Cấp độỨng dụng (UIApplication)Activity
Đa cửa sổMột scene hoạt độngNhiều Activity ở onPause

Khi nào Inactive xảy ra

Inactive trên iOS xảy ra trong một số kịch bản được xác định chặt chẽ. Người dùng mở Control Center (vuốt xuống từ góc trên bên phải trên iPhone X+ hoặc vuốt lên trên các mẫu cũ). Người dùng mở Notification Center (vuốt xuống từ góc trên bên trái). Cuộc gọi đến — hệ thống hiển thị màn hình cuộc gọi trên ứng dụng. Quyền hệ thống được yêu cầu — định vị, micrô, máy ảnh, danh bạ. Trên iPad, Slide Over hoặc Split View được khởi chạy — scene hoạt động trở thành Inactive.

Trên Android, onPause (tương đương của Inactive) xảy ra trong một loạt các tình huống rộng hơn. Mở hộp thoại (AlertDialog, DialogFragment). Một Activity bị che phủ một phần bởi Activity khác (ví dụ: Activity trong suốt để xác thực). Xoay màn hình (Activity được tạo lại, trình tự: onPause → onStop → onDestroy → onCreate → onStart → onResume). Chế độ đa cửa sổ — cửa sổ không hoạt động nhận onPause. Mỗi sự kiện này đều yêu cầu tạm dừng các hoạt động tốn nhiều tài nguyên để bảo toàn pin và hiệu suất.

swift
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) {
        // Ứng dụng chuyển sang Inactive — gián đoạn hệ thống
        print("Gián đoạn: Control Center, cuộc gọi hoặc cảnh báo hệ thống")

        // Tạm dừng các hoạt động nhạy cảm với thời gian
        pauseVideoPlayback()
        stopContinuousDataCollection()
        hideSensitiveInformation()

        // Thông báo cho các thành phần
        NotificationCenter.default.post(name: .systemInterruptionBegan, object: nil)
    }

    // Quay lại từ Inactive sang Active
    func applicationDidBecomeActive(_ application: UIApplication) {
        resumeVideoPlayback()
        restartDataCollection()
        NotificationCenter.default.post(name: .systemInterruptionEnded, object: nil)
    }

    private func pauseVideoPlayback() {
        // Tạm dừng video để âm thanh không bị chồng chéo
    }

    private func hideSensitiveInformation() {
        // Ẩn dữ liệu nhạy cảm khi chụp màn hình
        // Control Center/App Switcher chụp ảnh màn hình UI
    }
}

Mã cho thấy cách xử lý Inactive trong UIKit. applicationWillResignActive tạm dừng video, dừng thu thập dữ liệu và ẩn thông tin nhạy cảm. Điều này quan trọng vì khi Control Center hoặc App Switcher được mở, hệ thống chụp ảnh màn hình UI hiện tại — người dùng có thể thấy dữ liệu bí mật trong bản xem trước. NotificationCenter cho phép các thành phần ứng dụng đăng ký sự kiện gián đoạn.

Inactive trên iOS: Swift và UIKit

Trên iOS, Inactive được xử lý bởi một cặp phương thức: applicationWillResignActive (chuyển sang Inactive) và applicationDidBecomeActive (quay lại từ Inactive). Các phương thức này là một phần của UIApplicationDelegate và được gọi cho mỗi lần chuyển tiếp qua Inactive. Kể từ iOS 13 và UISceneDelegate, sceneWillResignActive và sceneDidBecomeActive đã được thêm vào cho các kịch bản đa cửa sổ.

SceneDelegate và Inactive đa cửa sổ

Trên iPad với iOS 13+, một ứng dụng có thể có nhiều scene (cửa sổ). Mỗi scene có vòng đời riêng. Một scene có thể trở thành Inactive (người dùng đã chuyển sang scene khác) trong khi scene khác vẫn Active. Đây là sự khác biệt quan trọng so với iPhone, nơi Inactive là trạng thái toàn cục cho toàn bộ ứng dụng. Khi phát triển cho iPad, bạn cần xử lý Inactive cho từng scene riêng biệt.

swift
import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    // Scene trở nên không hoạt động
    func sceneWillResignActive(_ scene: UIScene) {
        // Trên iPad scene này mất tiêu điểm, nhưng scene khác có thể hoạt động
        print("Scene mất hoạt động")

        // Tạm dừng các tác vụ của scene này
        pauseSceneSpecificOperations()
    }

    // Scene trở nên hoạt động
    func sceneDidBecomeActive(_ scene: UIScene) {
        print("Scene đã trở nên hoạt động")
        resumeSceneSpecificOperations()
    }

    private func pauseSceneSpecificOperations() {
        // Tạm dừng các hoạt động cụ thể cho scene này
    }

    private func resumeSceneSpecificOperations() {
        // Tiếp tục các hoạt động khi tiêu điểm quay lại
    }
}

// AppDelegate vẫn là điểm vào, ủy quyền cho các scene
@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(
        _ application: UIApplication,
        configurationForConnecting connectingSceneSession: UISceneSession,
        options: UIScene.ConnectionOptions
    ) -> UISceneConfiguration {
        return UISceneConfiguration(
            name: "Default Configuration",
            sessionRole: connectingSceneSession.role
        )
    }
}

Mã cho thấy SceneDelegate để xử lý Inactive ở cấp scene. sceneWillResignActive được gọi khi một cửa sổ cụ thể mất tiêu điểm — điều này có thể xảy ra khi chuyển đổi giữa các cửa sổ trên iPad. AppDelegate cấu hình UISceneConfiguration để hỗ trợ đa cửa sổ. Mỗi scene có trạng thái độc lập và nhà phát triển phải xử lý chúng riêng biệt.

Inactive trên Android: onPause và khả năng hiển thị

Trên Android, tương đương trực tiếp của Inactive trên iOS là phương thức onPause() của vòng đời Activity. Nó được gọi khi Activity mất tiêu điểm đầu vào nhưng có thể vẫn hiển thị. Các kịch bản điển hình: mở hộp thoại, khởi chạy Activity khác trong cùng ứng dụng, cuộc gọi đến, nhấn nút Home hoặc Recents. Trong onPause, nhà phát triển nên tạm dừng các hoạt động tốn nhiều tài nguyên — hoạt ảnh, phát video, làm việc với máy ảnh.

Một điểm khác biệt quan trọng của Android là onPause luôn xảy ra trước onStop, nhưng không ngược lại. Một Activity có thể nhận onPause mà không có onStop (ví dụ: khi mở Activity trong suốt). Ngoài ra, onPause có thể được gọi nhiều lần trong vòng đời của Activity — mỗi khi chuyển tiêu điểm. Không đặt logic một lần trong onPause — sử dụng onStop cho các hoạt động cuối cùng và onPause chỉ để tạm dừng các hành động tương tác.

kotlin
class VideoPlayerActivity : AppCompatActivity() {

    private var exoPlayer: ExoPlayer? = null
    private var currentPosition: Long = 0L

    override fun onPause() {
        super.onPause()
        // Ứng dụng mất tiêu điểm — tạm dừng video
        exoPlayer?.let { player ->
            if (player.isPlaying) {
                currentPosition = player.currentPosition
                player.pause()
            }
        }
        // Ẩn dữ liệu nhạy cảm (GDPR/màn hình ngân hàng)
        if (window.decorView.systemUiVisibility and
            View.SYSTEM_UI_FLAG_SECURE == 0
        ) {
            hideSensitiveOverlay()
        }
    }

    override fun onResume() {
        super.onResume()
        // Tiêu điểm quay lại — tiếp tục phát
        exoPlayer?.seekTo(currentPosition)
        exoPlayer?.play()
        showSensitiveOverlay()
    }

    private fun hideSensitiveOverlay() {
        // Đặt màn hình đen lên trên dữ liệu tài chính
    }
}

Mã cho thấy cách xử lý onPause đúng cho trình phát video. ExoPlayer bị tạm dừng khi mất tiêu điểm và vị trí phát được lưu lại. Khi quay lại onResume, trình phát tiếp tục phát từ vị trí đã lưu. Ngoài ra, một mẫu ẩn dữ liệu nhạy cảm được hiển thị — quan trọng cho các ứng dụng tài chính và y tế yêu cầu bảo vệ khỏi ảnh chụp màn hình khi chuyển đổi.

Các phương pháp hay nhất để xử lý Inactive

Quy tắc đầu tiên — ẩn dữ liệu bí mật khi chuyển sang Inactive. Khi người dùng mở Control Center hoặc App Switcher, iOS chụp ảnh màn hình hiện tại. Trên Android, tương tự, hệ thống hiển thị bản xem trước của Activity cuối cùng trong Recents. Sử dụng UIApplication.shouldSnapshotSecureApp (iOS 16+) hoặc FLAG_SECURE (Android) để bảo vệ màn hình bí mật.

Quy tắc thứ hai — tạm dừng hoạt ảnh và phương tiện. Inactive không phải thời điểm tốt để phát video hoặc hoạt ảnh vì người dùng không thể nhìn thấy chúng. Hơn nữa, phát ở nền có thể gây chồng chéo âm thanh với âm thanh hệ thống (nhạc chuông, thông báo). Dừng AVPlayer, ExoPlayer và UIView.animate khi chuyển sang Inactive và tiếp tục khi quay lại Active.

Quy tắc thứ ba — chặn nhập dữ liệu. Nếu ứng dụng có biểu mẫu nhập hoặc bản nháp, khóa bàn phím và trường nhập khi chuyển sang Inactive. Điều này ngăn nhập vô tình khi quay lại và bảo vệ khỏi việc chặn dữ liệu qua lớp phủ hệ thống. Trên iOS, từ bỏ người trả lời đầu tiên (view.endEditing(true)), trên Android — xóa tiêu điểm (currentFocus?.clearFocus()).

Quy tắc thứ tư — không thực hiện các hoạt động dài trong applicationWillResignActive hoặc onPause. Các phương thức này phải hoàn thành trong tích tắc. Nếu bạn cần lưu lượng lớn dữ liệu, hãy bắt đầu lưu trong luồng nền và hoàn thành trong applicationDidEnterBackground hoặc onStop. iOS cho 5 giây để thực thi applicationWillResignActive, sau đó hệ thống có thể buộc đóng ứng dụng.

swift
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
    }
}

// Sử dụng trong AppDelegate
func applicationWillResignActive(_ application: UIApplication) {
    SecureOverlayManager().showBlurOverlay()
}

func applicationDidBecomeActive(_ application: UIApplication) {
    SecureOverlayManager().removeBlurOverlay()
}

Mã cho thấy cách triển khai lớp phủ an toàn để bảo vệ dữ liệu khi chuyển sang Inactive. UIVisualEffectView với hiệu ứng làm mờ được đặt lên trên toàn bộ UI khi chuyển sang Inactive và được gỡ bỏ khi quay lại Active. Điều này đảm bảo dữ liệu bí mật sẽ không hiển thị trong ảnh chụp màn hình App Switcher và Control Center. Tương tự, bạn có thể sử dụng UIImageView với logo cho lớp phủ có thương hiệu.

Các câu hỏi thường gặp

Inactive có luôn xảy ra trước Background không?

Có. Inactive là trạng thái trung gian bắt buộc trước khi chuyển sang Background trên iOS. Ứng dụng không thể đi từ Active trực tiếp sang Background — đầu tiên nó trở thành Inactive, sau đó Background. Trên Android, tương tự, onPause luôn được gọi trước onStop. Điều này cho nhà phát triển cơ hội chuẩn bị dữ liệu để lưu trước khi hoàn toàn vào nền.

Ứng dụng có thể trở thành Inactive mà không có gián đoạn không?

Có. Trên iPad, khi khởi chạy Slide Over hoặc Split View, scene hoạt động trở thành Inactive, mặc dù không có gián đoạn hệ thống nào xảy ra — người dùng chỉ đang tương tác với scene khác. Đây là tính năng đa cửa sổ của iPadOS. Trên iPhone, Inactive luôn được kích hoạt bởi gián đoạn hệ thống — cuộc gọi, thông báo, Control Center hoặc Notification Center.

Ứng dụng có thể ở Inactive bao lâu?

Thông thường từ 0,1 đến 2 giây. Trong cuộc gọi đến có màn hình cuộc gọi — lên đến 30 giây (cho đến khi người dùng trả lời hoặc từ chối cuộc gọi). iOS không giới hạn thời gian ở Inactive một cách cưỡng chế, nhưng hệ thống có thể đóng ứng dụng nếu nó không phản hồi sự kiện (watchdog). Trên Android, onPause không có giới hạn thời gian, nhưng nên hoàn thành công việc trong 200 ms.

ScenePhase trong SwiftUI khi Inactive là gì?

ScenePhase.inactive — giá trị enum ScenePhase được đặt khi scene ở tiền cảnh nhưng không nhận sự kiện. Trong SwiftUI, bạn có thể quan sát nó qua @Environment(\.scenePhase) và phản ứng qua onChange. Khi chuyển từ .active sang .inactive, tạm dừng bộ đếm thời gian và hoạt ảnh. Khi quay lại .active, tiếp tục chúng. Khi chuyển sang .background, lưu trạng thái.

Có cần ẩn UI khi Inactive cho tất cả ứng dụng không?

Không, chỉ cho các ứng dụng xử lý dữ liệu bí mật: ngân hàng, y tế, doanh nghiệp và ứng dụng nhắn tin có trò chuyện riêng tư. Đối với trò chơi và ứng dụng giải trí, không cần ẩn UI. Tuy nhiên, tạm dừng trò chơi và âm thanh khi Inactive là thực hành tốt để tránh chồng chéo âm thanh với thông báo hệ thống. Apple khuyến nghị ẩn dữ liệu nhạy cảm nhưng không yêu cầu.

Tổng kết

  • Inactive — trạng thái chuyển tiếp giữa Active và Background, ứng dụng hiển thị nhưng không tương tác
  • Nguyên nhân — Control Center, Notification Center, cuộc gọi đến, quyền hệ thống, Siri, Apple Pay
  • Xử lý trên iOS — applicationWillResignActive để tạm dừng hoạt ảnh, phương tiện và ẩn dữ liệu nhạy cảm
  • SwiftUI — scenePhase .inactive qua Environment, onChange cho các tác dụng phụ
  • Android — onPause làm tương đương, hỗ trợ đa cửa sổ và che phủ một phần Activity
  • Bảo mật — lớp phủ làm mờ hoặc FLAG_SECURE để bảo vệ khỏi ảnh chụp màn hình App Switcher và Control Center
  • Tính chất tạm thời — Inactive kéo dài cho đến khi gián đoạn kết thúc, sau đó quay lại Active hoặc vào Background

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm