Những điểm chính
App Lifecycle là một máy trạng thái hữu hạn mô tả tất cả các trạng thái có thể của một ứng dụng di động và sự chuyển đổi giữa chúng. Mỗi trạng thái xác định liệu ứng dụng có thể thực thi mã, hiển thị giao diện người dùng và tiêu thụ tài nguyên hay không. iOS và Android có các mô hình tương tự nhưng không giống hệt nhau — sự khác biệt xuất phát từ kiến trúc hệ điều hành: iOS sử dụng kiểm soát bộ nhớ nghiêm ngặt (trạng thái suspended), trong khi Android sử dụng quản lý tiến trình linh hoạt thông qua onSaveInstanceState.
Trong iOS, vòng đời gắn chặt với tiền cảnh/hậu cảnh: ứng dụng hoặc đang hoạt động hoặc bị tạm ngưng. Trong Android, vòng đời chi tiết hơn — một Activity/Cửa sổ trải qua 6+ trạng thái, và bản thân tiến trình có một vòng đời bổ sung thông qua ProcessLifecycleOwner. Các ứng dụng hiện đại (từ năm 2024) ngày càng sử dụng các mẫu kiến trúc dựa trên vòng đời: SwiftUI Lifecycle (iOS 16+) thông qua môi trường .scenePhase, Compose Lifecycle thông qua LifecycleEventObserver. Các mẫu này tự động xử lý chuyển đổi ngữ cảnh và ngăn rò rỉ bộ nhớ. Theo Google, xử lý vòng đời đúng cách trong Android giảm mức tiêu thụ bộ nhớ 30–40 % khi làm việc trong nền.
Trong iOS, vòng đời ứng dụng được quản lý thông qua lớp UIApplicationDelegate (AppDelegate). Các phương thức chính: application(_:didFinishLaunchingWithOptions:) — khởi tạo lần đầu tiên; applicationDidBecomeActive — ứng dụng hiển thị và sẵn sàng tương tác; applicationWillResignActive — chuyển sang trạng thái không hoạt động (cuộc gọi đến, đóng bảng thông báo); applicationDidEnterBackground — ứng dụng bị ẩn, ~5 giây để lưu dữ liệu; applicationWillEnterForeground — quay lại từ nền; applicationWillTerminate — kết thúc (chỉ được gọi cho ứng dụng cũ không có suspended).
Bắt đầu từ iOS 13, Apple đã giới thiệu SceneDelegate (UISceneDelegate) để hỗ trợ các ứng dụng đa cửa sổ trên iPad và macOS Catalyst. SceneDelegate quản lý vòng đời của từng cảnh (cửa sổ) riêng lẻ: scene(_:willConnectTo:options:) — tạo cảnh; sceneDidBecomeActive — cảnh hoạt động; sceneWillResignActive — cảnh mất tiêu điểm; sceneDidEnterBackground — cảnh bị ẩn. AppDelegate xử lý các sự kiện toàn cầu (tải dữ liệu, thông báo đẩy), trong khi SceneDelegate xử lý trạng thái giao diện người dùng của từng cửa sổ. Trong SwiftUI, vòng đời được xử lý thông qua giá trị môi trường @Environment(\.scenePhase): .active, .inactive, .background — điều này cung cấp một API thống nhất cho cả ứng dụng SwiftUI và UIKit.
Trong Android, vòng đời bắt đầu với lớp Application — một singleton được tạo trước bất kỳ Activity nào. Phương thức Application.onCreate() là điểm vào đầu tiên, được sử dụng để khởi tạo toàn cầu (Analytics, DI, Crash Reporting). Sau đó, Activity được khởi chạy với trình tự: onCreate() → onStart() → onResume(). Khi thu nhỏ: onPause() → onStop() → onSaveInstanceState(). Khi bị hủy: onDestroy(). Khi quay lại: onRestart() → onStart() → onResume().
ProcessLifecycleOwner (từ AndroidX Lifecycle 2.2+) theo dõi vòng đời của toàn bộ tiến trình, không phải một Activity riêng lẻ. Nó cung cấp hai trạng thái: ON_RESUME (ứng dụng ở tiền cảnh) và ON_STOP (ứng dụng bị ẩn). ProcessLifecycleOwner giải quyết vấn đề «khi nào ứng dụng vào nền» ở cấp độ tiến trình — điều này rất quan trọng cho SDK, thư viện và ứng dụng mô-đun. Trong Jetpack Compose, vòng đời được quản lý thông qua LifecycleEventObserver và collectAsStateWithLifecycle, tự động tạm ngưng thu thập dữ liệu ở chế độ nền. Android 14 (API 34) đã thêm thông báo vòng đời dịch vụ tiền cảnh qua Service.onTimeout — dịch vụ phải hoàn thành trong vòng 6 giờ, nếu không hệ thống sẽ buộc dừng nó.
| iOS | Android | Mô tả |
|---|---|---|
| Not Running | — | Ứng dụng chưa được khởi động |
| didFinishLaunching | Application.onCreate | Khởi tạo đầu tiên khi khởi động |
| Active | onResume | Ứng dụng hiển thị và đang nhận đầu vào |
| Inactive | onPause | Mất tiêu điểm tạm thời (cuộc gọi, bảng thông báo) |
| Background | onStop | Ứng dụng bị ẩn, mã có thể đang thực thi |
| Suspended | — | Mã không thực thi, bộ nhớ được dự trữ |
| Will Terminate | onDestroy | Ứng dụng đang kết thúc |
Sự khác biệt chính: iOS buộc ứng dụng chuyển sang Suspended (mã ngừng thực thi) 5-10 giây sau khi vào nền. Android cho phép làm việc trong nền (dịch vụ, WorkManager) trong thời gian dài hơn, nhưng với các giới hạn của Chế độ Doze (Android 6+) và hạn chế nền (Android 12+). ProcessLifecycleOwner trong Android tương đương với UIApplicationDidEnterBackgroundNotification trong iOS, với điểm khác biệt là nó kích hoạt khi bất kỳ chuyển đổi nào vào nền, không chỉ sau khi mất tiêu điểm.
Triển khai AppDelegate cơ bản xử lý tất cả trạng thái vòng đời. Lưu dữ liệu khi chuyển sang nền và cập nhật giao diện người dùng khi quay lại.
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Analytics.shared.initialize()
return true
}
func applicationDidBecomeActive(_ application: UIApplication) {
NotificationCenter.default.post(name: .appDidBecomeActive, object: nil)
}
func applicationWillResignActive(_ application: UIApplication) {
NotificationCenter.default.post(name: .appWillResignActive, object: nil)
}
func applicationDidEnterBackground(_ application: UIApplication) {
CoreDataManager.shared.saveContext()
UserDefaults.standard.synchronize()
}
func applicationWillEnterForeground(_ application: UIApplication) {
NetworkManager.shared.refreshSession()
}
}
AppDelegate là điểm trung tâm của vòng đời. applicationDidEnterBackground là phương thức quan trọng: iOS cho ~5 giây để lưu. applicationDidBecomeActive — cập nhật giao diện người dùng, khởi động lại hoạt ảnh. Đối với SceneDelegate (iOS 13+), logic vòng đời được phân phối qua các cảnh: sceneDidBecomeActive / sceneDidEnterBackground quản lý các cửa sổ riêng lẻ.
SceneDelegate cho ứng dụng iPad đa cửa sổ. Mỗi cảnh có vòng đời riêng, độc lập với các cửa sổ khác.
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
func sceneDidBecomeActive(_ scene: UIScene) {
PlayerManager.shared.resume()
}
func sceneDidEnterBackground(_ scene: UIScene) {
PlayerManager.shared.pause()
CoreDataManager.shared.saveContext()
}
func sceneDidDisconnect(_ scene: UIScene) {
PlayerManager.shared.cleanup()
}
}
SceneDelegate quản lý vòng đời của một cảnh riêng lẻ. sceneDidBecomeActive / sceneDidEnterBackground tương đương với các phương thức AppDelegate cho một cửa sổ cụ thể. sceneDidDisconnect được gọi khi một cảnh đóng (người dùng đã đóng cửa sổ trên iPad). Để tương thích với iOS 12 trở xuống, AppDelegate phải sao chép logic SceneDelegate. Trong iOS 17+, bạn có thể sử dụng @Observable để tự động tạm dừng/tiếp tục tác vụ dựa trên scenePhase.
ProcessLifecycleOwner theo dõi khi ứng dụng ở tiền cảnh/hậu cảnh ở cấp độ tiến trình. Đây là cách tiếp cận tối ưu để quản lý vòng đời toàn cầu.
import android.app.Application
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
}
}
class AppLifecycleObserver : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onEnterForeground() {
Analytics.shared.onForeground()
NetworkMonitor.shared.start()
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onEnterBackground() {
Analytics.shared.onBackground()
NetworkMonitor.shared.stop()
}
}
ProcessLifecycleOwner là cách duy nhất chính xác để theo dõi chuyển đổi sang nền ở cấp độ ứng dụng. ON_START kích hoạt khi ứng dụng hiển thị (tiền cảnh), ON_STOP — khi bị ẩn hoàn toàn (hậu cảnh). Không giống như vòng đời Activity, ProcessLifecycleOwner không gắn với một màn hình cụ thể. Đối với Jetpack Compose, hãy sử dụng LifecycleResumeEffect hoặc collectAsStateWithLifecycle thay vì quan sát thủ công.
ViewModel + Lifecycle là kiến trúc Android chính xác để quản lý vòng đời. ViewModel tự động được dọn dẹp khi onDestroy, ngăn rò rỉ.
import androidx.lifecycle.ViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
class TimerViewModel : ViewModel() {
private val _time = MutableLiveData<Long>()
val time: LiveData<Long> = _time
private var startTime = System.currentTimeMillis()
init {
updateTime()
}
private fun updateTime() {
_time.value = System.currentTimeMillis() - startTime
}
override fun onCleared() {
super.onCleared()
Logger.d("ViewModel cleared — giải phóng tài nguyên")
}
}
// Trong Activity
class TimerActivity : AppCompatActivity() {
private val viewModel: TimerViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Logger.d("Activity created")
}
override fun onResume() {
super.onResume()
viewModel.time.observe(this) { Logger.d("Time: $it") }
}
override fun onPause() {
super.onPause()
Logger.d("Activity paused — tạm dừng hoạt ảnh")
}
override fun onDestroy() {
super.onDestroy()
Logger.d("Activity destroyed — dọn dẹp")
}
}
ViewModel tồn tại qua xoay màn hình và chỉ bị hủy khi Activity kết thúc. onCleared() là nơi giải phóng tài nguyên và hủy đăng ký luồng. LiveData tự động tạm dừng quan sát khi onPause và tiếp tục khi onResume — điều này cung cấp bảo vệ chống rò rỉ và sự cố khi làm việc trong nền. Trong Compose, hãy sử dụng collectAsStateWithLifecycle() cho mục đích tương tự.
Câu hỏi thường gặp
Khi thu nhỏ, ứng dụng chuyển từ hoạt động sang không hoạt động (ngắn), sau đó vào nền. Sau vài giây, hệ thống có thể chuyển nó sang suspended — mã ngừng thực thi, bộ nhớ được dự trữ. Khi thiếu bộ nhớ, hệ thống kết thúc ứng dụng bị tạm ngưng (willTerminate không được gọi). Lưu dữ liệu của bạn trong applicationDidEnterBackground — đây là điểm đảm bảo cuối cùng để lưu.
Tối thiểu bắt buộc: applicationDidEnterBackground — lưu dữ liệu người dùng; applicationWillEnterForeground — cập nhật giao diện người dùng; trong Android onPause — tạm dừng hoạt ảnh/cảm biến. ProcessLifecycleOwner đơn giản hóa việc xử lý: onResume — onPause cho tiền cảnh, onStart — onStop cho khả năng hiển thị. Xử lý các trạng thái khác khi cần — không phải tất cả trạng thái đều quan trọng cho mọi ứng dụng.
AppDelegate là đại biểu toàn cầu của toàn bộ ứng dụng (khởi động, chuyển đổi nền). SceneDelegate (iOS 13+) quản lý vòng đời của một cửa sổ riêng lẻ (cảnh) — trong ứng dụng iPad đa cửa sổ, mỗi cảnh có vòng đời riêng. Đối với iOS 12 trở xuống, tất cả vòng đời được xử lý qua AppDelegate. Với iPadOS 16+, SceneDelegate là bắt buộc cho Stage Manager.
ProcessLifecycleOwner là một thành phần từ AndroidX Lifecycle theo dõi vòng đời của toàn bộ ứng dụng (tiến trình), không phải một Activity riêng lẻ. Nó cung cấp hai sự kiện chính: ON_RESUME (ứng dụng ở tiền cảnh) và ON_STOP (ứng dụng ở hậu cảnh). Nó được sử dụng để khởi tạo/dọn dẹp SDK, phân tích, giám sát mạng — bất cứ thứ gì cần phản ứng với việc ứng dụng chuyển sang nền, bất kể màn hình hiện tại.
Trong Jetpack Compose, hãy sử dụng LifecycleEventObserver thông qua LocalLifecycleOwner.current.lifecycle hoặc hàm collectAsStateWithLifecycle(). Đối với màn hình Compose, hãy sử dụng LifecycleResumeEffect — tương tự DisposableEffect, chạy khi onResume và dọn dẹp khi onPause. lifecycleScope.launchWhenResumed — một coroutine tự động tạm ngưng trong nền.
Tổng kết
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.
Đọc thêm