onRestart — Android Activity 라이프사이클의 메서드로, 시스템이 Activity를 Stopped 상태에서 Started 상태로 반환하기 전에 호출합니다. onRestart는 이전에 다른 화면에 의해 숨겨졌거나 백그라운드로 최소화된 Activity가 사용자에게 다시 표시됨을 알립니다. onRestart에서 개발자는 오래된 데이터를 업데이트하고, 목록을 다시 로드하며, Activity가 보이지 않는 동안 변경되었을 수 있는 UI 상태를 복원합니다. Google Android Vitals(2025)에 따르면 onRestart를 사용하여 데이터를 업데이트하는 앱은 화면으로 돌아올 때 잘못된 정보 표시 사례가 25% 더 적습니다. Android Developers 문서는 onRestart를 Activity가 화면에 다시 나타나기 전의 준비 단계로 설명합니다.
핵심 요점
onRestart — Android가 onStart 직전에, Activity가 보이지 않는 Stopped 상태에서 다시 표시 상태로 돌아올 때 호출하는 콜백 메서드입니다. 이 메서드는 Activity가 다시 표시될 때만 호출된다는 점에서 독특합니다 — 인스턴스의 첫 번째 생성 시 시퀀스는 onCreate로 시작하여 onRestart를 건너뜁니다. 전체 사이클: onCreate → onStart → onResume(첫 실행) 또는 onRestart → onStart → onResume(이후 표시).
Android 시스템의 관점에서 onRestart는 Activity가 복귀를 준비할 수 있도록 하는 최적화입니다: 리포지토리에서 데이터 업데이트, UI 상태 동기화, 네트워크 연결 확인. Activity가 포커스를 얻을 때마다 호출되는 onResume(대화상자나 시스템 메뉴에서 돌아올 때도 포함)과 달리 onRestart는 완전한 숨김 및 복귀 주기 중에만 트리거됩니다. 이로 인해 onRestart는 부분적인 포커스 손실 시 필요하지 않은 “무거운” 업데이트 작업에 이상적인 장소가 됩니다.
Android Activity 라이프사이클 사양에 따르면 onStop과 onRestart 사이의 시간 간격은 몇 초(사용자가 빠르게 전환)에서 몇 시간(앱이 백그라운드에 있었고 사용자가 돌아옴)까지 될 수 있습니다. 이 시간 동안 원격 소스(API, DB)의 데이터가 변경되었을 수 있으므로 onRestart는 최신 상태 확인을 위한 자연스러운 지점입니다.
onRestart는 Activity가 Stopped 상태에서 돌아올 때만 호출됩니다. Activity는 onStop이 호출된 후 이 상태에 진입합니다. 아래는 onRestart로 이어지는 모든 시나리오입니다.
onRestart 호출 시나리오:
onRestart가 호출되지 않는 경우: 화면 회전 시(Activity가 소멸되고 onCreate를 통해 다시 생성됨), 대화상자에서 돌아올 때(Activity가 onStop에 들어가지 않음, onPause → onResume만), 프로세스 종료 시(Activity가 다시 생성됨).
onRestart와 onCreate는 Activity를 복원하는 두 가지 다른 접근 방식입니다. 둘 중 선택은 Activity가 완전히 소멸되었는지 아니면 단순히 숨겨졌는지에 따라 달라집니다.
| 특성 | onRestart | onCreate |
|---|---|---|
| 호출 시기 | Activity가 Stopped에서 돌아옴 | Activity가 처음 생성되거나 소멸 후 |
| 상태 보존 | 예 — ViewModel 및 필드가 살아 있음 | 아니오 — 모든 것이 새로 생성됨 |
| Bundle | 전달되지 않음 | 전달됨 (savedInstanceState) |
| 일반적인 작업 | 데이터 업데이트, UI 새로고침 | View 초기화, LiveData 구독 |
| 호출 빈도 | 돌아올 때마다 | 한 번 또는 소멸 후 |
선택 규칙: View 초기화 및 LiveData/StateFlow 구독은 onCreate에서 수행합니다(Fragment의 경우 onViewCreated). 데이터 업데이트, 목록 다시 로드 및 상태 확인은 onRestart에서 수행합니다. ViewModel을 통해 데이터를 로드하는 경우 onRestart는 ViewModel에서 refresh() 메서드를 호출하기만 하면 되고, View는 반응형 스트림을 통해 업데이트된 데이터를 구독합니다.
Google 권장: onRestart에서 onCreate 로직을 복제하지 마세요. ViewModel에서 현재 데이터를 로드하는 refresh() 메서드를 추출하고 onRestart에서 호출하세요. 이렇게 하면 깔끔한 MVVM 아키텍처가 유지되고 코드 중복이 제거됩니다.
onRestart는 화면으로 돌아올 때마다 수행되어야 하지만 처음 열 때는 필요하지 않은 작업에 이상적인 장소입니다. 일반적인 시나리오는 다음과 같습니다:
viewModel.refreshItems()를 호출하세요.onRestart에서 하지 말아야 할 것: View를 다시 초기화하지 마세요 — Activity가 소멸되지 않았으므로 살아 있습니다. LiveData를 다시 구독하지 마세요 — onCreate의 구독이 아직 유효합니다. 새 Fragment를 만들지 마세요 — 이미 FragmentManager에 있습니다.
가장 중요한 예외: 앱 프로세스가 시스템에 의해 종료된 경우 onRestart가 호출되지 않습니다. 이는 상태 복원을 onRestart에 의존할 때 개발자가 자주 놓치는 핵심 사항입니다.
프로세스 종료 시:
이를 방지하는 방법: 중요한 상태를 항상 onSaveInstanceState(Bundle)(onStop 전에 호출됨)에 저장하거나 ViewModel에서 SavedStateHandle을 사용하세요. onCreate에서 savedInstanceState를 확인하세요: null이 아니면 Bundle에서 상태를 복원하고, null이면 새 데이터를 로드하세요.
Google Android Vitals에 따르면 백그라운드에서 오랜 시간 후 Activity로 돌아오는 약 7%가 프로세스 종료 후에 발생합니다. 즉, onRestart를 호출했어야 할 Activity 15개 중 1개는 실제로 onCreate를 통해 진행됩니다. 이 시나리오를 무시하는 것은 “돌아온 후 빈 화면” 버그의 주요 원인 중 하나입니다.
Activity는 편집 화면에서 돌아온 후 작업 목록을 업데이트하기 위해 onRestart에서 viewModel.refreshTasks()를 호출합니다.
class TaskListActivity : AppCompatActivity() {
private val viewModel: TaskViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_task_list)
viewModel.tasks.observe(this) { tasks ->
Log.d("TaskList", "${tasks.size}개 작업 수신")
}
}
override fun onRestart() {
super.onRestart()
Log.d("TaskList", "onRestart: 작업 목록 업데이트 중")
viewModel.refreshTasks()
}
}
class TaskViewModel : ViewModel() {
private val _tasks = MutableLiveData<List<Task>>()
val tasks: LiveData<List<Task>> get() = _tasks
fun refreshTasks() {
viewModelScope.launch {
_tasks.value = TaskRepository().getAllTasks()
}
}
}
ViewModel.refreshTasks()는 리포지토리에서 현재 데이터를 로드합니다. LiveData는 자동으로 Activity에 데이터 변경을 알립니다 — UI는 추가 코드 없이 업데이트됩니다. onRestart는 새 구독을 만들지 않습니다 — 이미 onCreate에서 설정되었습니다.
Activity는 돌아올 때 토큰 유효성을 확인하고 필요한 경우 로그인으로 리디렉션합니다.
class ProfileActivity : AppCompatActivity() {
private val authManager = AuthManager()
private val launcher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { Log.d("Profile", "로그인 화면에서 돌아옴") }
override fun onRestart() {
super.onRestart()
if (!authManager.isTokenValid()) {
Log.d("Profile", "토큰 만료 — 로그인으로 리디렉션")
launcher.launch(Intent(this, LoginActivity::class.java))
}
}
}
class AuthManager {
fun isTokenValid(): Boolean {
val expiry = SharedPreferencesManager().getTokenExpiry()
return System.currentTimeMillis() < expiry
}
}
사용자가 앱을 오랫동안 최소화하고 토큰이 만료된 후 돌아온 경우 onRestart가 로그인 화면으로 리디렉션합니다. 이는 만료된 토큰으로 요청을 시도할 때 API 오류를 방지합니다. 참고: 확인은 onResume이 아닌 onRestart에 있습니다. 이는 대화상자에서 돌아올 때 불필요한 확인을 피하기 위함입니다.
Fragment는 데이터를 업데이트하기 위해 LifecycleObserver를 통해 onRestart를 사용합니다.
class FeedFragment : Fragment() {
private val viewModel: FeedViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycle.addObserver(object : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_RESTART)
fun onRestart() {
Log.d("FeedFragment", "LifecycleObserver를 통한 onRestart")
viewModel.refreshFeed()
}
})
}
}
Fragment에서 onRestart를 재정의하는 대신 LifecycleObserver가 사용됩니다 — 상속 없이 라이프사이클 이벤트 로직을 추가할 수 있는 더 유연한 접근 방식입니다. ViewLifecycleOwner는 observer가 View 범위 내에서 유지되도록 보장합니다(onDestroyView를 초과하여 지속되지 않음).
자주 묻는 질문
onResume은 Activity가 포커스를 얻을 때마다 호출됩니다 — 대화상자나 시스템 메뉴에서 돌아올 때도 포함됩니다(Activity가 onStop에 들어가지 않음). onRestart는 Activity가 완전히 숨겨졌던 Stopped 상태에서 돌아올 때만 호출됩니다. onRestart는 “무거운” 업데이트를 위한 더 좁은 이벤트이고, onResume은 가벼운 작업(제목 변경, 시간 업데이트)을 위한 것입니다.
아니요, 불가능합니다. onRestart는 onStop과 쌍을 이루는 메서드입니다. onRestart는 Activity가 onStop을 통과한 후에만 호출됩니다. Activity가 onStop에 들어가지 않은 경우(예: 대화상자가 열린 경우), 돌아올 때 onRestart는 호출되지 않고 onResume만 호출됩니다.
에뮬레이터에서 Home(홈 버튼)을 누르세요 — Activity가 최소화되고 onStop을 받습니다. 그런 다음 최근 앱 또는 런처를 통해 앱을 여세요 — Activity가 onRestart → onStart → onResume을 받습니다. 디버깅을 위해 onRestart에 중단점이 있는 Debug 또는 Activity 태그가 있는 Log.d를 사용하세요.
onRestart에서 포착되지 않은 예외는 Force Close를 발생시킵니다. 시스템은 라이프사이클 콜백에서 예외를 포착하지 않습니다. onRestart에서 예외를 발생시킬 수 있는 작업(try-catch 없는 네트워크 요청, null View 작업)을 수행하는 경우 try-catch로 감싸세요.
아니요. onRestart는 Stopped 상태에서 돌아오는 살아 있는 Activity에 대해서만 호출됩니다. onRestart의 isFinishing()은 항상 false입니다. isFinishing() 확인은 onPause(데이터 저장)와 onDestroy(재생성과 종료 구분)에서 의미가 있습니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.