Principais conclusões
App Lifecycle é uma máquina de estados finitos que descreve todos os estados possíveis de um aplicativo móvel e as transições entre eles. Cada estado determina se o aplicativo pode executar código, exibir UI e consumir recursos. iOS e Android têm modelos semelhantes, mas não idênticos — as diferenças decorrem da arquitetura do SO: iOS usa controle rígido de memória (estado suspended), enquanto Android usa gerenciamento flexível de processos através do onSaveInstanceState.
No iOS, o ciclo de vida está estritamente ligado ao primeiro plano/fundo: o aplicativo está ativo ou suspenso. No Android, o ciclo de vida é mais granular — uma Activity/Janela passa por 6+ estados, e o próprio processo tem um ciclo de vida adicional através do ProcessLifecycleOwner. Aplicativos modernos (desde 2024) usam cada vez mais padrões de arquitetura baseados em ciclo de vida: SwiftUI Lifecycle (iOS 16+) através do ambiente .scenePhase, Compose Lifecycle através do LifecycleEventObserver. Esses padrões lidam automaticamente com a troca de contexto e previnem vazamentos de memória. De acordo com o Google, o manuseio correto do ciclo de vida no Android reduz o consumo de memória em 30–40 % durante o trabalho em segundo plano.
No iOS, o ciclo de vida do aplicativo é gerenciado através da classe UIApplicationDelegate (AppDelegate). Os principais métodos: application(_:didFinishLaunchingWithOptions:) — inicialização no primeiro lançamento; applicationDidBecomeActive — o aplicativo está visível e pronto para interação; applicationWillResignActive — transição para estado inativo (chamada recebida, fechamento da cortina de notificações); applicationDidEnterBackground — o aplicativo está oculto, ~5 segundos para salvar dados; applicationWillEnterForeground — retorno do segundo plano; applicationWillTerminate — encerramento (chamado apenas para aplicativos mais antigos sem suspended).
A partir do iOS 13, a Apple introduziu o SceneDelegate (UISceneDelegate) para suportar aplicativos multijanela no iPad e macOS Catalyst. O SceneDelegate gerencia o ciclo de vida de cada cena (janela) individual: scene(_:willConnectTo:options:) — criação da cena; sceneDidBecomeActive — cena ativa; sceneWillResignActive — cena perde o foco; sceneDidEnterBackground — cena oculta. O AppDelegate lida com eventos globais (carregamento de dados, notificações push), enquanto o SceneDelegate lida com o estado da interface do usuário de cada janela. No SwiftUI, o ciclo de vida é gerenciado através do valor de ambiente @Environment(\.scenePhase): .active, .inactive, .background — isso fornece uma API unificada para aplicativos SwiftUI e UIKit.
No Android, o ciclo de vida começa com a classe Application — um singleton criado antes de qualquer Activity. O método Application.onCreate() é o primeiro ponto de entrada, usado para inicialização global (Analytics, DI, Crash Reporting). Depois disso, a Activity é iniciada com a sequência: onCreate() → onStart() → onResume(). Ao minimizar: onPause() → onStop() → onSaveInstanceState(). Ao destruir: onDestroy(). Ao retornar: onRestart() → onStart() → onResume().
ProcessLifecycleOwner (do AndroidX Lifecycle 2.2+) rastreia o ciclo de vida de todo o processo, não de uma Activity individual. Ele fornece dois estados: ON_RESUME (aplicativo em primeiro plano) e ON_STOP (aplicativo oculto). O ProcessLifecycleOwner resolve o problema de «quando o aplicativo foi para o segundo plano» no nível do processo — isso é crítico para SDKs, bibliotecas e aplicativos modulares. No Jetpack Compose, o ciclo de vida é gerenciado através de LifecycleEventObserver e collectAsStateWithLifecycle, que suspende automaticamente a coleta de dados no modo de segundo plano. O Android 14 (API 34) adicionou notificação de ciclo de vida do serviço em primeiro plano através de Service.onTimeout — o serviço deve ser concluído em 6 horas, caso contrário o sistema o interrompe à força.
| iOS | Android | Descrição |
|---|---|---|
| Not Running | — | O aplicativo não foi iniciado |
| didFinishLaunching | Application.onCreate | Primeira inicialização ao iniciar |
| Active | onResume | O aplicativo está visível e aceitando entrada |
| Inactive | onPause | Perda temporária de foco (chamada, cortina de notificações) |
| Background | onStop | O aplicativo está oculto, o código pode estar em execução |
| Suspended | — | O código não está em execução, a memória está reservada |
| Will Terminate | onDestroy | O aplicativo está terminando |
A principal diferença: o iOS força a transição do aplicativo para Suspended (o código para de executar) 5-10 segundos após entrar em segundo plano. O Android permite trabalho em segundo plano (serviços, WorkManager) por um período mais longo, mas com limitações do Modo Doze (Android 6+) e restrições de segundo plano (Android 12+). ProcessLifecycleOwner no Android é o equivalente de UIApplicationDidEnterBackgroundNotification no iOS, com a diferença de que é acionado em qualquer transição para segundo plano, não apenas após perder o foco.
Implementação básica do AppDelegate lidando com todos os estados do ciclo de vida. Salvando dados ao transitar para o segundo plano e atualizando a UI ao retornar.
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()
}
}
O AppDelegate é o ponto central do ciclo de vida. applicationDidEnterBackground é um método crítico: o iOS dá ~5 segundos para salvar. applicationDidBecomeActive — atualize a UI, reinicie animações. Para SceneDelegate (iOS 13+), a lógica do ciclo de vida é distribuída entre cenas: sceneDidBecomeActive / sceneDidEnterBackground gerenciam janelas individuais.
SceneDelegate para aplicativos iPad multijanela. Cada cena tem seu próprio ciclo de vida, independente de outras janelas.
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 gerencia o ciclo de vida de uma cena individual. sceneDidBecomeActive / sceneDidEnterBackground são os equivalentes dos métodos AppDelegate para uma janela específica. sceneDidDisconnect é chamado quando uma cena é fechada (o usuário fechou uma janela no iPad). Para compatibilidade com iOS 12 e versões anteriores, o AppDelegate deve duplicar a lógica do SceneDelegate. No iOS 17+, você pode usar @Observable para pausar/retomar automaticamente tarefas com base no scenePhase.
O ProcessLifecycleOwner rastreia quando o aplicativo está em primeiro plano/fundo no nível do processo. Esta é a abordagem ideal para o gerenciamento global do ciclo de vida.
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 é a única maneira correta de rastrear a transição para segundo plano no nível do aplicativo. ON_START é acionado quando o aplicativo se torna visível (primeiro plano), ON_STOP — quando está completamente oculto (segundo plano). Ao contrário do ciclo de vida da Activity, o ProcessLifecycleOwner não está vinculado a uma tela específica. Para Jetpack Compose, use LifecycleResumeEffect ou collectAsStateWithLifecycle em vez de observação manual.
ViewModel + Lifecycle é a arquitetura correta do Android para gerenciamento do ciclo de vida. O ViewModel é limpo automaticamente no onDestroy, prevenindo vazamentos.
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 — liberando recursos")
}
}
// Na 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 — pausando animações")
}
override fun onDestroy() {
super.onDestroy()
Logger.d("Activity destroyed — limpeza")
}
}
ViewModel sobrevive à rotação da tela e é destruído apenas quando a Activity é finalizada. onCleared() é o local para liberar recursos e cancelar assinaturas de streams. O LiveData pausa automaticamente a observação no onPause e retoma no onResume — isso fornece proteção contra vazamentos e falhas durante o trabalho em segundo plano. No Compose, use collectAsStateWithLifecycle() para o mesmo propósito.
Perguntas frequentes
Ao minimizar, o aplicativo transita de ativo para inativo (brevemente), depois para segundo plano. Após alguns segundos, o sistema pode movê-lo para suspended — o código para de executar, a memória é reservada. Quando a memória está baixa, o sistema encerra o aplicativo suspenso (willTerminate não é chamado). Salve seus dados no applicationDidEnterBackground — este é o último ponto garantido para salvar.
Mínimo obrigatório: applicationDidEnterBackground — salvar dados do usuário; applicationWillEnterForeground — atualizar a UI; no Android onPause — pausar animações/sensores. O ProcessLifecycleOwner simplifica o manuseio: onResume — onPause para primeiro plano, onStart — onStop para visibilidade. Lide com outros estados conforme necessário — nem todos os estados são críticos para cada aplicativo.
O AppDelegate é o delegado global de todo o aplicativo (inicialização, transição para segundo plano). O SceneDelegate (iOS 13+) gerencia o ciclo de vida de uma janela individual (cena) — em aplicativos iPad multijanela, cada cena tem seu próprio ciclo de vida. Para iOS 12 e versões anteriores, todo o ciclo de vida é tratado através do AppDelegate. Com iPadOS 16+, o SceneDelegate é obrigatório para o Stage Manager.
ProcessLifecycleOwner é um componente do AndroidX Lifecycle que rastreia o ciclo de vida de todo o aplicativo (processo), não de uma Activity individual. Ele fornece dois eventos principais: ON_RESUME (aplicativo em primeiro plano) e ON_STOP (aplicativo em segundo plano). É usado para inicialização/limpeza de SDKs, análises, monitores de rede — tudo que deve reagir à transição do aplicativo para segundo plano, independentemente da tela atual.
No Jetpack Compose, use LifecycleEventObserver através de LocalLifecycleOwner.current.lifecycle ou a função collectAsStateWithLifecycle(). Para telas do Compose, use LifecycleResumeEffect — semelhante ao DisposableEffect, que executa no onResume e limpa no onPause. lifecycleScope.launchWhenResumed — uma corrotina que suspende automaticamente em segundo plano.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também