안드로이드를 개발하다 보면 기본 화면 및 UI에 대한 설정이 필요한 경우가 있습니다.

하지만 onCreate 와 onPostCreate로 구분지어 작업해야하는 경우가 있습니다. 아래 내용은 해당 함수의 차이점을 알아보고 사용 예를 알아보아요.

 

onCreate와 onPostCreate의 주요 차이는 호출 시점UI 초기화 완료 여부입니다. 이 두 메서드는 모두 Activity의 생명 주기에서 호출되지만, 각 메서드의 호출 시점과 목적이 다릅니다.

 

1. onCreate

  • 호출 시점: Activity가 생성되는 가장 초기 단계에서 호출됩니다.
  • 목적: Activity의 기본 초기화 작업을 수행합니다.
  • 주요 작업:
    • setContentView로 레이아웃을 설정합니다.
    • ViewModel, DataBinding, Intent 데이터 초기화 등 초기 설정을 수행합니다.

onCreate에서는 UI 요소가 아직 완전히 레이아웃되지 않았기 때문에 크기나 위치 같은 동적 레이아웃 정보를 정확하게 얻을 수 없습니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)  // 레이아웃 설정
    // 초기화 작업 수행
}

 

2. onPostCreate

  • 호출 시점: onCreate가 끝난 직후, Activity가 초기화된 후 호출됩니다.
  • 목적: Activity가 완전히 생성된 후 추가 UI 설정이나 동적 레이아웃 작업을 수행합니다.
  • 주요 작업:
    • onCreate 이후 추가적인 UI 작업을 수행하기 적합한 메서드입니다.
    • 상태 표시줄이나 window 관련 설정을 하는 데 유용합니다.

onPostCreate는 Activity의 초기화가 끝난 후 호출되므로, UI가 그려지기 전에 수행해야 하는 추가 설정이나 window 설정 등을 안전하게 처리할 수 있습니다.

override fun onPostCreate(savedInstanceState: Bundle?) {
    super.onPostCreate(savedInstanceState)
    // 추가 UI 설정, 예를 들어 상태 표시줄 색상 설정
}

 

onCreate와 onPostCreate의 차이 요약

매서드 호출시점 주요목적 작업 예시
onCreate Activity 초기 생성 단계 기본 초기화 및 레이아웃 설정 setContentView, Intent 처리
onPostCreate onCreate가 완료된 직후 추가 UI 설정 및 window 설정 상태 표시줄, 전체 화면 설정

 

언제 onPostCreate를 사용하는 것이 좋은가요?

  • 상태 표시줄, window 속성 설정 등 UI가 완전히 초기화되기 전에 설정해야 하는 추가적인 UI 작업이 있는 경우.
  • onCreate에서만 처리할 수 없는 추가적인 레이아웃 초기화나 window 설정이 필요한 경우.

따라서 onCreate는 기본 초기화 및 레이아웃 설정에 주로 사용되고, onPostCreate는 추가 UI 설정 작업에 더 적합한 메서드입니다.

 

오늘 withContext라는 개념에 대해 알아보겠습니다.

 

withContext란?

Android의 withContext는 Kotlin 코루틴에서 코루틴 컨텍스트를 변경하면서 비동기 작업을 수행하는 데 사용됩니다. 간단히 말해서, 현재 코루틴을 특정 디스패처로 이동하여, 그 환경에서 특정 코드를 실행하도록 합니다. Android에서 일반적으로 UI 스레드와 백그라운드 스레드 간 전환을 쉽게 하도록 도와주는 중요한 도구입니다.

 

기본 개념

withContext는 비동기 코드 블록을 지정한 디스패처에서 실행하게 하며, 특정 코드가 완료될 때까지 일시 중단합니다. 코드가 완료되면 원래의 컨텍스트로 돌아가서 이후 작업을 이어서 수행할 수 있습니다.

 

주요 사용 사례

1. UI 스레드와 백그라운드 스레드 간 전환
Android에서는 네트워크 요청이나 데이터베이스 작업 같은 오래 걸리는 작업을 메인(UI) 스레드에서 수행하지 않도록 권장합니다. 이런 경우 Dispatchers.IO 또는 Dispatchers.Default와 함께 withContext를 사용하여 백그라운드 스레드에서 작업을 처리할 수 있습니다.

// 코루틴 내부에서 사용 예시
val result = withContext(Dispatchers.IO) {
    // 네트워크 호출이나 DB 작업 등
    myDatabase.queryData()
}
// 결과를 UI에 반영 (메인 스레드에서 수행됨)
textView.text = result

 

2. CPU 집약적인 작업
이미지 처리나 데이터 변환 등 CPU를 많이 사용하는 작업을 Dispatchers.Default로 옮겨 CPU 리소스를 최적화하면서 메인 스레드를 차단하지 않도록 할 수 있습니다.

val processedData = withContext(Dispatchers.Default) {
    processData(data) // CPU 집약적인 작업
}

 

3. UI 업데이트 작업
네트워크 작업이나 데이터 처리가 완료된 후 다시 UI 작업으로 돌아올 때 Dispatchers.Main을 사용해 메인 스레드에서 UI를 안전하게 업데이트할 수 있습니다.

withContext(Dispatchers.Main) {
    textView.text = "Data Loaded"
}

 

장점

  • 컨텍스트 전환이 간단: withContext를 사용하면 코드 블록 내에서 비동기 작업을 손쉽게 컨텍스트 변경을 통해 실행할 수 있습니다.
  • 코드 가독성: 콜백이나 복잡한 핸들러를 사용하지 않아도 되므로, 코드를 더욱 간결하고 이해하기 쉽게 만듭니다.
  • 효율적인 리소스 사용: 필요에 따라 적절한 디스패처로 전환하여 리소스를 효율적으로 사용할 수 있습니다.

 

Android에서 withContext는 비동기 작업을 적절한 스레드에서 수행할 수 있도록 도와주는 코루틴 기능입니다. 이를 통해 UI 스레드와 백그라운드 스레드 간의 전환을 쉽게 구현할 수 있으며, Dispatchers.Main, Dispatchers.IO, Dispatchers.Default 등의 디스패처를 지정하여 효율적이고 안전하게 비동기 작업을 수행할 수 있습니다.

 

@AndroidEntryPoint는 Hilt의 핵심 어노테이션으로, Android 컴포넌트(Activity, Fragment, Service 등)에 의존성 주입을 활성화하는 역할을 합니다. 이를 통해 Hilt는 해당 컴포넌트가 생성될 때 자동으로 필요한 의존성을 주입할 수 있게 됩니다.

 

사용 방법

Hilt를 사용하면 각 Android 컴포넌트에 @AndroidEntryPoint를 추가하고, Hilt가 제공하는 의존성을 주입받을 수 있습니다. 예를 들어, Activity나 Fragment에 @AndroidEntryPoint를 추가하고, ViewModel, Repository, ApiService 등과 같은 의존성을 주입받을 수 있습니다.

예시

1. Activity에서 사용

@AndroidEntryPoint
class GameActivity : AppCompatActivity() {

    // Hilt가 GameViewModel을 주입
    private val gameViewModel: GameViewModel by viewModels()

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

        // ViewModel을 사용하여 게임 데이터를 가져오는 로직
    }
}

2. Fragment에서 사용

@AndroidEntryPoint
class GameFragment : Fragment(R.layout.fragment_game) {

    // Hilt가 GameViewModel을 주입
    private val gameViewModel: GameViewModel by viewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // ViewModel을 사용하여 데이터를 가져오는 등의 작업
    }
}

 

3. Service에서 사용

@AndroidEntryPoint
class GameService : Service() {

    // Hilt가 GameRepository를 주입
    @Inject lateinit var gameRepository: GameRepository

    override fun onBind(intent: Intent?): IBinder? {
        // 서비스에서 gameRepository를 사용
        return null
    }
}

 

@AndroidEntryPoint의 역할

  • @AndroidEntryPoint가 선언된 클래스에서는 해당 클래스가 Hilt에서 의존성 주입을 받을 수 있도록 처리됩니다.
  • Hilt는 해당 컴포넌트가 생성될 때 자동으로 주입할 의존성을 찾아서 삽입합니다.
  • @AndroidEntryPoint가 선언된 컴포넌트에서는 @Inject 어노테이션을 사용하여 의존성을 주입받을 수 있습니다.
  • @AndroidEntryPoint를 사용하면, ViewModel, Repository, Network 모듈 등 필요한 객체들이 컴포넌트에 자동으로 주입되며, 별도의 의존성 생성 코드 없이 DI 패턴을 구현할 수 있습니다.

주의사항

  • @AndroidEntryPoint는 Hilt의 DI 기능을 사용할 수 있는 컴포넌트에서만 사용해야 하며, Activity, Fragment, Service, BroadcastReceiver와 같은 Android 컴포넌트에서 사용됩니다.
  • @AndroidEntryPoint가 없는 컴포넌트에서는 Hilt를 통한 의존성 주입을 사용할 수 없습니다.

요약

@AndroidEntryPoint는 Hilt의 의존성 주입을 Android 컴포넌트에 적용할 때 사용되는 어노테이션으로, 이를 통해 Activity, Fragment, Service 등에서 의존성 주입을 쉽게 할 수 있습니다.

@Provides는 Dagger-Hilt 또는 Dagger에서 사용되는 어노테이션으로, 의존성을 제공하는 메서드를 정의할 때 사용됩니다. 이 어노테이션은 객체 생성 로직을 제공하는 메서드에 붙여주며, Dagger/Hilt가 해당 메서드를 호출하여 필요한 의존성을 주입할 수 있도록 합니다.

 

기본 개념

 

  • @Provides는 Hilt 모듈 안에서 사용되어 특정 타입의 객체를 생성하고, 이 객체를 의존성으로 제공하는 역할을 합니다.
  • Hilt는 @Provides가 붙은 메서드를 통해 의존성을 생성하고, 필요한 곳에 주입합니다.

예시

@Module
@InstallIn(SingletonComponent::class)  // SingletonComponent에 설치
object NetworkModule {

    // ApiService를 제공하는 메서드
    @Provides
    fun provideApiService(): ApiService {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

 

 

위 코드에서 @Provides 어노테이션은 provideApiService 메서드에 적용되어 ApiService 객체를 생성하고 제공하는 역할을 합니다. Hilt는 ApiService를 요청하는 곳에 해당 객체를 주입할 수 있습니다.

 

@Provides 사용의 필요성

 

  • 자동 객체 생성을 위한 설정: Hilt는 자동으로 객체를 생성하지 않기 때문에, @Provides를 사용하여 객체 생성 방법을 명시해야 합니다. Hilt는 이 메서드를 호출하여 객체를 생성하고, 해당 객체를 필요한 곳에 주입합니다.
  • 매개변수 기반 의존성 제공: 의존성의 매개변수로 다른 객체들이 필요한 경우, @Provides를 사용하여 의존성을 동적으로 제공할 수 있습니다.

매개변수 사용 예시

다른 객체를 주입해야 하는 경우 @Provides 메서드의 매개변수로 의존성을 받을 수 있습니다. Hilt는 이 의존성들을 자동으로 해결하여 @Provides 메서드에 전달합니다.

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Provides
    fun provideUserManager(apiService: ApiService, userPreferences: UserPreferences): UserManager {
        return UserManager(apiService, userPreferences)
    }

    @Provides
    fun provideApiService(): ApiService {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }

    @Provides
    fun provideUserPreferences(): UserPreferences {
        return UserPreferences()
    }
}

 

 

위 예제에서 provideUserManager 메서드는 ApiService와 UserPreferences 의존성을 매개변수로 받아 UserManager 객체를 반환합니다. Hilt는 이 메서드를 호출할 때 필요한 의존성들을 자동으로 주입합니다.

 

@Provides와 @Inject의 차이

  • @Provides: 의존성 제공 방법을 명시적으로 정의하는 방법입니다. 주로 객체 생성 로직을 포함한 메서드에 사용됩니다.
  • @Inject: 의존성을 자동으로 주입받을 때 사용하는 어노테이션입니다. 주로 클래스의 생성자나 필드에 사용됩니다.

@Inject는 의존성을 주입하는 곳에 사용되며, @Provides는 의존성을 제공하는 곳에 사용됩니다.

 

@Provides와 @Module

  • @Module 어노테이션이 붙은 클래스 안에서 @Provides 메서드를 정의하여, Hilt가 의존성 주입을 처리할 수 있도록 합니다.
  • @Module은 Dagger 또는 Hilt가 객체를 제공할 수 있도록 의존성의 생성 방법을 정의하는 곳입니다.

결론

@Provides는 의존성 객체를 생성하여 제공하는 메서드에 사용됩니다. Hilt는 @Provides로 정의된 메서드를 호출하여 필요한 의존성을 생성하고, 다른 곳에서 이 객체를 주입받을 수 있게 해줍니다. 객체 생성 방법을 명시적으로 제공해야 할 때 @Provides를 사용하며, 이를 통해 의존성 주입의 흐름을 관리합니다.

@InstallIn 어노테이션은 Dagger-Hilt에서 사용되는 어노테이션으로, Hilt 모듈어디에 설치할 것인지 지정하는 역할을 합니다. 이 어노테이션은 Dagger-Hilt에서 DI (Dependency Injection) 설정을 쉽게 해주는 중요한 요소입니다.

 

 

기본 개념

Dagger-Hilt에서는 의존성 주입을 위해 여러 모듈을 정의하고, 이 모듈이 어떤 컴포넌트(범위)에 포함될지 지정해야 합니다. 이때 @InstallIn 어노테이션을 사용하여, 특정 모듈을 어떤 컴포넌트에 설치할 것인지 정의할 수 있습니다. @InstallIn은 기본적으로 @Component 또는 @Subcomponent와 같은 Dagger의 컴포넌트 개념에 대응됩니다.

 

사용 방법

Dagger-Hilt에서는 주로 다음과 같은 컴포넌트를 사용하여 의존성을 주입합니다:

  • SingletonComponent: 애플리케이션의 전체 생애 주기 동안 하나의 인스턴스만 유지되는 컴포넌트입니다.
  • ActivityComponent: 액티비티의 생애 주기 동안 의존성 주입을 관리하는 컴포넌트입니다.
  • FragmentComponent: 프래그먼트의 생애 주기 동안 의존성 주입을 관리하는 컴포넌트입니다.
  • ViewModelComponent: ViewModel의 생애 주기 동안 의존성 주입을 관리하는 컴포넌트입니다.

이 외에도 다양한 생애 주기별 컴포넌트가 존재합니다.

 

예시

1. @InstallIn(SingletonComponent::class)

SingletonComponent에 설치된 모듈은 애플리케이션 전역에서 한 번만 생성되어 사용됩니다. 주로 애플리케이션 단위로 한 번만 생성해야 하는 객체들에 대해 사용합니다.

 
@Module
@InstallIn(SingletonComponent::class)  // SingletonComponent에 설치
object NetworkModule {

    @Provides
    fun provideApiService(): ApiService {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

 

이렇게 설정하면 ApiService는 애플리케이션의 전체 생애 주기 동안 하나의 인스턴스로만 존재하게 됩니다.

2. @InstallIn(ActivityComponent::class)

ActivityComponent에 설치된 모듈은 액티비티의 생애 주기에 맞춰 의존성을 관리합니다. 즉, 액티비티가 존재하는 동안에만 해당 객체가 존재합니다.

@Module
@InstallIn(ActivityComponent::class)  // ActivityComponent에 설치
object ActivityModule {

    @Provides
    fun provideSomeDependency(): SomeDependency {
        return SomeDependency()
    }
}
 

이렇게 설정하면 SomeDependency는 액티비티가 존재하는 동안에만 사용됩니다.

3. @InstallIn(ViewModelComponent::class)

ViewModelComponent에 설치된 모듈은 ViewModel의 생애 주기 동안에 의존성을 관리합니다. ViewModel이 생성되고 파괴될 때 해당 의존성도 주입되고 파괴됩니다.

 
@Module
@InstallIn(ViewModelComponent::class)  // ViewModelComponent에 설치
object ViewModelModule {

    @Provides
    fun provideGameRepository(): GameRepository {
        return GameRepositoryImpl()
    }
}

이렇게 설정하면 GameRepository는 ViewModel의 생애 주기 동안에만 사용됩니다.

요약

  • @InstallIn 어노테이션은 Hilt 모듈을 특정 컴포넌트에 설치하여 해당 컴포넌트의 생애 주기에 맞는 의존성 관리를 할 수 있게 합니다.
  • SingletonComponent, ActivityComponent, FragmentComponent, ViewModelComponent와 같은 다양한 컴포넌트를 사용하여 의존성의 생애 주기를 조절할 수 있습니다.
  • 이 방식은 Hilt의 의존성 주입을 더 효율적으로 관리할 수 있게 해주며, 주입할 객체의 범위를 명확하게 정의할 수 있게 해줍니다.

+ Recent posts