onCreate — 그것이 뭐인가, Android에서 Activity 초기화

저자: IT Sectr 게시일: 2026-03-03 읽는 시간: 10 분

onCreate는 Android에서 Activity와 Fragment 라이프사이클의 첫 번째이자 유일한 필수 메소드입니다. 시스템은 컴포넌트를 생성할 때 한 번 그것을 호출하며, 이전에 저장된 상태를 가진 Bundle 파라미터를 전달합니다. onCreate 내부에서 개발자는 사용자 인터펄이스를 초기화하고, View 요소를 바인드하고, 이벤트 핸들러를 구성하며, savedInstanceState에서 데이터를 복구합니다. onCreate의 올바른 구현 없이는 어떤 Android 애플리케이션도 실행할 수 없습니다 — 그것은 각 화면에 대한 입구 포인트입니다. 일반적인 Activity 라이프사이클에 대한 자세한 정보는 글 Activity Lifecycle을 읽어주세요.

주요 요점

  • onCreate — 첫 번째이자 유일한 필수 라이프사이클 메소드; Activity 또는 Fragment를 생성할 때 한 번 호출됨
  • Bundle 파라미터 — savedInstanceState는 onSaveInstanceState에 저장된 데이터를 포함하거나, Activity가 처음 생성되면 null임
  • setContentView — Activity에 대한 onCreate 내의 필수 호출; XML 레이아웃을 코드에 바인드함
  • UI 초기화 — findViewById, RecyclerView 어댑터 설정, 클릭 리스너 설정 — 일반적인 onCreate 작업
  • Fragment.onCreate — Activity와 달림: 여기서는 setContentView가 호출되지 않으며, 레이아웃이 onCreateView를 통해 전달됨
  • 시간 제한 — onCreate는 5초 내에 완료되어야 함 (ANR threshold), 긴 작업은 백그라운드 스레드로 이동됨
  • ViewModel과 onCreate — onCreate에서 ViewModel을 초기화하면 화면 회전에서 데이터가 손실되지 않고 유지됨

Android에서 onCreate란

onCreate는 Android가 Activity 또는 Fragment의 새 인스턴스를 생성할 때 호출하는 콜백 메소드입니다. 이것은 사용자 화면 코드로의 첫 번째 입구 포인트입니다. onCreate가 호출되기 전에는 어떤 사용자 코드도 실행되지 않습니다. 시스템은 메소드에 Bundle 파라미터를 전달하며, 이전에 저장된 데이터(재생성 시) 또는 null(첫 실행 시)을 포함합니다.

onCreate 메소드는 android.app.Activity 클래스와 androidx.fragment.app.Fragment 클래스에 정의되어 있습니다. 두 변형 모두 비슷한 작업을 수행합니다: 컴포넌트 초기화, UI 설정 및 상태 복구. 그러나 구체적인 구현은 다릅니다 — Activity는 레이아웃을 로드하기 위해 setContentView를 사용하는 반면, Fragment는 onCreateView를 통해 View를 반환합니다. 개발자는 Activity에서 적어도 onCreate를 오버라이드해야 합니다 — 이것 없이는 Android가 화면을 표시할 수 없습니다.

onCreate는 Activity 인스턴스의 완전한 라이프사이클로 한 번 급격하게 호출됩니다. 화면 회전에서도 새 Activity 인스턴스는 이전 인스턴스의 Bundle을 가진 새 onCreate 호출을 받습니다. 이로서 onCreate는 일회 초기화에 이상적인 곳이 됩니다: 데이터 로드, 어댑터 생성, Dagger 또는 Hilt를 통한 DI 컴포넌트 설정.

Activity에서 onCreate

Activity에서 onCreate 메소드는 네 가지 주요 작업을 수행합니다: 레이아웃 마크업 로드, View 요소 초기화, Bundle에서 상태 복구 및 기본 이벤트 핸들러 설정. onCreate의 필수 최소 코드는 super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)을 호출하는 것입니다.

kotlin
class MainActivity : AppCompatActivity() {
    private var binding: ActivityMainBinding? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ViewBinding — findViewById의 현대적인 대체
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding?.root)

        // binding을 사용한 초기화
        binding?.apply {
            welcomeText.text = getString(R.string.welcome)
            startButton.setOnClickListener { startGame() }
        }

        // 상태 복구
        if (savedInstanceState != null) {
            score = savedInstanceState.getInt("score", 0)
            binding?.scoreText?.text = score.toString()
        }
    }
}

현대 실무에서는 findViewById 대신 ViewBinding을 사용합니다. ViewBinding은 컴파일 시점에 ActivityMainBinding 클래스를 생성하여 잘못된 ID에 의한 오류를 제거하고 보일러플레이트 코드를 줄입니다. Google은 Android Studio 3.6부터 Activity 및 Fragment에서 View에 앱소드하는 표준 방법으로 ViewBinding을 권장합니다.

onCreate에서 작업 순서는 엄격해야 합니다: 먼저 super, 그 다음 setContentView, 그리고 다른 모든 것을 수행합니다. setContentView 전에 findViewById를 호출하면 null이 반환됩니다 — 아직 레이아웃이 로드되지 않았고, View 요소가 계층 구조에 존재하지 않습니다. 이것은 초보 Android 개발자들이 하는 가장 흔한 실수 중 하나입니다.

Fragment에서 onCreate

Fragment에서 onCreate는 Activity와 다릅니다: 여기서는 setContentView가 호출되지 않고, UI와 관계없는 데이터 초기화만 수행됩니다. Fragment는 컴포넌트 생성과 View 생성을 두 개의 별도 메소드로 분리합니다: onCreate(한 번 호출) 그리고 onCreateView(View가 생성되거나 재생성될 때마다 호출).

kotlin
class UserListFragment : Fragment() {
    private lateinit var viewModel: UserViewModel
    private var binding: FragmentUserListBinding? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // ViewModel 초기화 — View 재생성을 검내냄
        viewModel = ViewModelProvider(this)[UserViewModel::class.java]

        // FragmentManager로부터 인수
        arguments?.let {
            viewModel.loadUser(it.getString("user_id") ?: "")
        }

        // 회전 시 저장
        retainInstance = true
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentUserListBinding.inflate(inflater, container, false)
        return binding!!.root
    }
}

Activity와 Fragment onCreate의 주요 차이점: Fragment의 onCreate는 View와 관련된 코드를 포함해서는 안 됩니다. 왜냐하면 View는 깩기되고 재생성될 수 있고(예: ViewPager 탭 전환 시), onCreate는 한 번만 호출되기 때문입니다. 데이터 로드, ViewModel 설정 및 어댑터 초기화는 onCreate의 작업이고, View 바인드는 onViewCreated의 작업입니다.

savedInstanceState와 상태 복구

onCreate에서 savedInstanceState 파라미터는 Activity 또는 Fragment의 임시 상태를 저장하고 복구하는 메커니즘입니다. 시스템이 Activity를 깩 때(화면 회전, 메모리 부족), onSaveInstanceState()를 호출하며 개발자는 Bundle에 키-값 엔트리를 넣습니다. 새 인스턴스가 생성되면 이 Bundle이 onCreate에서 반환됩니다.

Bundle은 다음 데이터 타입을 지원합니다: String, Integer, Boolean, Long, Float, Double, 그 배열, 그리고 Parcelable 및 Serializable 객체. 복잡한 객체에는 Parcelable이 사용됩니다 — Android에 국한된 더 늨산 시리얼라이제이션 메커니즘입니다. Bundle 크기는 약 500 KB로 제한됩니다 — 제한을 초과하면 TransactionTooLargeException이 발생합니다.

kotlin
companion object {
    private const val KEY_USER_NAME = "user_name"
    private const val KEY_SCORE = "score"
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_game)

    if (savedInstanceState != null) {
        userName = savedInstanceState.getString(KEY_USER_NAME) ?: ""
        currentScore = savedInstanceState.getInt(KEY_SCORE)
    }
}

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putString(KEY_USER_NAME, userName)
    outState.putInt(KEY_SCORE, currentScore)
}

이 점을 이해하는 것이 중요합니다: 사용자가 finish() 또는 뒤로가기 버튼으로 Activity를 명시적으로 닫을 때 onSaveInstanceState가 호출되지 않습니다. 시스템은 사용자가 의식적으로 작업을 종료하고 있으며 상태를 저장할 필요가 없다고 간주합니다. 따라서 장기 데이터 저장에 savedInstanceState에만 의존할 수 없습니다 — Room, DataStore 또는 SharedPreferences를 사용하세요.

onCreate 타이밍 및 제한

onCreate는 메인(UI) 스레드에서 실행되며, 시스템은 Activity를 화면에 표시하기 전에 그것이 완료되기를 기다립니다. onCreate가 5초 이상 걸리면 시스템은 ANR(Application Not Responding) 대화상자를 표시하고 사용자에게 애플리케이션을 닫을 것을 물어보겠요. 네트워크에서 데이터 로드하거나 데이터베이스에서 읽는 것같은 긴 작업은 백그라운드 스레드로 이동되어야 합니다.

Google Android Performance (2025) 권장에 따르면, 중간급 기기에서 onCreate는 1초 미만에 완료되어야 합니다. 이를 위해: 게으른 초기화(Kotlin에서 lazy delegate)를 사용하고, 무거운 데이터 로드를 onResume 또는 코루틴으로 미루고, 간허히 사용되는 UI 컴포넌트에 ViewStub을 적용하며, Android Vitals을 통해 시작 시간을 프로파일링하세요.

kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // 게으른 초기화 — 객체가 처음 액세스 시에만 생성됨
    val heavyData by lazy {
        HeavyDataLoader.load()
    }

    // lifecycleScope를 통한 백그라운드 스레드에서 데이터 로드
    lifecycleScope.launch(Dispatchers.IO) {
        val users = userDao.getAllUsers()
        withContext(Dispatchers.Main) {
            adapter.submitList(users)
        }
    }
}

프로파일링 도구: Android Studio Profiler(CPU 탭)은 각 메소드의 정확한 실행 시간을 보여줍니다. Android Vitals(Google Play Console)에서 “콜드 스타트 시간” 메트릭을 추적할 수 있습니다 — Activity의 onCreate가 500 ms를 초과하면 콘솔이 이를 성능 문제로 표시합니다. IT Sectr에서는 CI 파이프라인에서 각 Activity의 시작 시간을 자동 제어하기 위해 Macrobenchmark 테스트를 사용합니다.

ViewModel과 onCreate

ViewModel은 화면 회전에서도 유지되어야 하는 데이터를 onCreate에서 초기화하는 가장 좋은 방법입니다. ViewModel은 onCreate에서 ViewModelProvider를 통해 생성되고 구성 변경에 자동으로 보존됩니다. 회전 후 Activity가 재생성되면 ViewModel은 메모리에 그대로 남아 있고, onCreate는 데이터 손실 없이 동일한 ViewModel을 받습니다.

kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_profile)

    // ViewModel은 한 번 생성되고 구성 변경을 검내냄
    val viewModel: ProfileViewModel =
        ViewModelProvider(this)[ProfileViewModel::class.java]

    // LiveData 관찰 — 데이터가 바변될 때 UI가 자동으로 업데이트됨
    viewModel.user.observe(this) { user ->
        binding?.userName?.text = user.name
        binding?.userEmail?.text = user.email
    }

    // ViewModel이 막 생성된 경우 데이터 로드
    if (savedInstanceState == null) {
        viewModel.loadProfile(userId)
    }
}

ViewModel + LiveData/StateFlow의 조합은 Bundle에 수동 저장 없이 화면 회전 문제를 해결합니다. ViewModel은 메모리에 데이터를 저장하고, LiveData는 재생성 시 Activity를 자동으로 재구독하며, StateFlow(Kotlin Coroutines에서)는 코루틴 지원으로 반응성을 추가합니다. 이것은 Google이 Guide to App Architecture에서 권장하는 표준 아키텍처입니다.

onCreate 사용시 일반적인 실수

숙련된 개발자도 onCreate에서 티픽한 실수를 합니다. 가장 흔한 다섯 가지 문제와 피하는 방법을 살펴보겠습니다.

setContentView 전에 View 사용하기

가장 흔한 실수는 setContentView를 호출하기 전에 findViewById를 통해 View를 찾으려는 것입니다. 모든 View 요소는 레이아웃 인플레이션 시점에 생성되뭀로, setContentView 전에 findViewById를 호출하면 null이 반환되고 View를 사용하려면 NullPointerException이 발생합니다. 해결 방법: 엄격한 순서 — 먼저 super, 그 다음 setContentView, 그 다음 findViewById 또는 ViewBinding.

긴 작업으로 UI 스레드 차단하기

네트워크에서 데이터 로드, 데이터베이스에서 읽거나 큰 배열을 onCreate에서 직접 처리하면 첫 번째 프레임의 렌더링이 차단됩니다. 사용자는 onCreate가 완료될 때까지 검은 화면을 보게 되며, 이는 애플리케이션 속도에 대한 인식을 저하시킵니다. 해결 방법: 비동기 작업에는 lifecycleScope.launch를 사용하고, 로드가 완료될 때까지 스켈렆톤(UI placeholder)을 표시하세요.

savedInstanceState 무시

화면 회전 시 Bundle에서 상태를 복구하지 않으면 사용자는 저장되지 않은 모든 입력을 잃게 됩니다: 폼 필드의 텍스트, 스크롤 위치, 선택된 항목들. 해결 방법: 상태 손실 가능성이 낮다고 생각되더라도, 데이터 복구를 위해 onCreate에서 항상 savedInstanceState != null을 확인하세요.

익명 클래스를 통한 메모리 누수

onCreate에서의 익명 클래스와 람다는 Activity가 깩인 후에도 음시적으로 Activity에 대한 참조를 유지할 수 있습니다. 예를 들어, onCreate에서 생성된 Handler는 Activity가 깩인 후에도 지연된 작업을 계속 실행합니다. 해결 방법: 깩을 때 작업을 자동으로 취소하는 LifecycleObserver, ViewModel 및 lifecycleScope를 사용하세요.

Fragment.onCreate에서 과다한 초기화

Fragment.onCreate에서 View를 초기화하는 것은 논리적인 오류입니다. 왜냐하면 View는 onCreate 호출 없이 재생성될 수 있기 때문입니다. onCreate에서 리스너를 설정하지만 onCreateView에서 View를 바인드하면, 재생성 시 리스너가 구 View에 그대로 남아 있게 됩니다. 해결 방법: 모든 View-관련 작업은 onViewCreated에서 수행하고, onCreate는 데이터 레이어 초기화만을 위해 남겨두세요.

자주 묻는 질문

Activity에서 onCreate를 오버라이드하는 것이 필수인가요?

네, onCreate 오버라이드는 필수입니다. 사용자 인터펄이스를 표시하는 모든 Activity에 대해 필수적입니다. 이것 없이는 setContentView를 호출하고 XML 레이아웃을 로드하는 것이 불가능합니다. Activity에 UI가 없는 경우(예: 투명한 Activity 스탭)에도 onCreate는 오버라이드되지만, setContentView는 호출하지 않습니다.

Activity를 깩지 않고 onCreate를 다시 호출할 수 있나요?

아니요. 동일한 Activity 인스턴스에 대해 onCreate를 다시 호출할 수 없습니다. Activity가 깩기고 재생성되면(화면 회전, 메모리 부족), 그것은 새 인스턴스이며 새 onCreate 호출가 있습니다. 예외는 recreate() 메소드로, Activity를 강제로 깩고 재생성하지만, 이것은 새 인스턴스의 재생성입니다.

super.onCreate을 호출하지 않으면 어떻게 됩나요?

super.onCreate(savedInstanceState)를 호출하지 않으면, Android Runtime이 SuperNotCalledException을 발생시키고 애플리케이션이 충돌합니다. 시스템은 오버라이드된 각 라이프사이클 메소드가 자신의 super 버전을 호출하도록 엄격하게 요구합니다 — 이는 내부 상태 머신의 올바른 작동을 보장합니다.

Activity의 onCreate와 Fragment의 onCreate는 어떻게 다릅니까?

주요 차이점: Activity의 onCreate는 setContentView를 통해 UI를 로드하지만, Fragment의 onCreate는 데이터를 초기화합니다. Fragment는 별도의 메소드 onCreateView에서 View를 생성하며, 이는 여러 번 호출될 수 있지만(탭 전환 시), Fragment.onCreate는 Fragment 인스턴스 수명 동안 한 번만 호출됩니다.

onCreate에서 다른 메소드로 데이터를 전달하려면 어떻게 하나요?

onCreate에서 초기화된 데이터는 Activity 또는 Fragment의 클래스 필드에 저장됩니다. 예를 들어, private lateinit var binding: ActivityMainBinding은 클래스 레벨에서 선언되고, onCreate에서 초기화되고, 그 후의 모든 메소드에서 사용 가능합니다. 화면 회전에서 유지되어야 하는 데이터에는 LiveData 또는 StateFlow를 사용한 ViewModel을 사용하세요.

요약

  • onCreate — 필수 라이프사이클 메소드, Activity 또는 Fragment 생성 시 한 번 호출됨
  • setContentView — Activity에 필수 호출, XML 레이아웃 로드; Fragment의 경우, 레이아웃이 onCreateView를 통해 로드됨
  • savedInstanceState — 재생성 시 저장된 상태를 가진 Bundle; 처음 실행 시 null
  • 시간 제한 — onCreate는 1초 미만에 완료되어야 하며, 긴 작업은 코루틴으로 이동됨
  • ViewModel — onCreate에서 ViewModel 초기화는 화면 회전 시 데이터 손실 문제를 해결함
  • Fragment vs Activity — Fragment.onCreate는 UI 코드가 없고, Activity.onCreate는 setContentView로 레이아웃 로드
  • 다섯 가지 티픽한 실수 — setContentView 전 View 작업, UI 차단, Bundle 무시, 메모리 누수, Fragment.onCreate에서 UI 코드

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기