목차
들어가기 전에
context를 사용하는 구글 credemtialManager을 뷰모델로 옮기는 것이 좋다는 코드 리뷰를 들었다.
memory leak (메모리 누수)란?
메모리 누수는 애플리케이션이 더이상 필요하지 않은 객체에 대한 참조를 유지함으로써 해당 객체에 할당된 메모리를 회수할 수 없어 나타나는 오류를 말한다.
메모리 누수가 언제 발생하는지 확인하기 위한 시도들
질문 정리
상황
AuthAcivity에서 ViewModel로 CredentialManager 관련 google login 코드를 이동하고싶다.
CredentialManager 객체 구성 시 activityContext를 사용하고 있다.
viewModel에서 CredentialManager 객체를 어떤 방식으로 구성해주어야할까?
➡️ 1. 뷰 모델의 requestGoogleLogin에서 인자로 받는 AuthActivity Context를 받아서 credentialManager 객체를 구성해주는 방법
fun requestGoogleLogin(context: Context) {
val credentialManager = CredentialManager.create(context)
viewModelScope.launch {
runCatching {
credentialManager.getCredential(
request = credentialRequest,
context = context,
)
}
````
}
}
결과
🚨메모리 leak 발생!
그러나 화면 회전과 같은 구성 변경 시 이 경우에도 메모리 누수가 발생하였다!
➡️ 2. GoogleAuthModule을 ViewModelComponet로 지정 후 에서 credentialManager 객체 구성 시 context를 @ActivityContext로 지정해줄 경우
ViewModelComponent 주입 시 @ActivityContext를 이용할 수 없음
@Provides
fun provideCredentialManager(
@ActivityContext context: Context,
): CredentialManager {
return CredentialManager.create(context)
}
@Inject
lateinit var credentialManager: CredentialManager
fun requestGoogleLogin(context: Context) {
viewModelScope.launch {
runCatching {
credentialManager.getCredential(
request = credentialRequest,
context = context,
)
}
````
}
}
🚨에러
[Dagger/MissingBinding] @dagger.hilt.android.qualifiers.ActivityContext android.content.Context cannot be provided without an @Provides-annotated method.
@dagger.hilt.android.qualifiers.ActivityContext android.content.Context is injected at
[com.teamfilmo.filmo.app.FilmoApp_HiltComponents.ViewModelC] com.teamfilmo.filmo.data.remote.di.GoogleAuthModule.provideCredentialManager(context)
androidx.credentials.CredentialManager is injected at
[com.teamfilmo.filmo.app.FilmoApp_HiltComponents.ViewModelC] com.teamfilmo.filmo.ui.auth.AuthViewModel.credentialManager
com.teamfilmo.filmo.ui.auth.AuthViewModel is injected at
[com.teamfilmo.filmo.app.FilmoApp_HiltComponents.ViewModelC] com.teamfilmo.filmo.ui.auth.AuthViewModel_HiltModules.BindsModule.binds(arg0)
@dagger.hilt.android.internal.lifecycle.HiltViewModelMap java.util.Map<java.lang.Class<?>,javax.inject.Provider<androidx.lifecycle.ViewModel>> is requested at
[com.teamfilmo.filmo.app.FilmoApp_HiltComponents.ViewModelC] dagger.hilt.android.internal.lifecycle.HiltViewModelFactory.ViewModelFactoriesEntryPoint.getHiltViewModelMap() [com.teamfilmo.filmo.app.FilmoApp_HiltComponents.SingletonC �� com.teamfilmo.filmo.app.FilmoApp_HiltComponents.ActivityRetainedC �� com.teamfilmo.filmo.app.FilmoApp_HiltComponents.ViewModelC]
Note: @dagger.hilt.android.qualifiers.ActivityContext android.content.Context is provided in the following other components:
[com.teamfilmo.filmo.app.FilmoApp_HiltComponents.ActivityC] dagger.hilt.android.internal.modules.ActivityModule.provideContext(��)
➡️ 3. GoogleAuthModule을 ViewModelComponent로 지정 후 에서 credentialManager 객체 구성 시 context를 @ApplicationContext로 지정해줄 경우
@Provides
fun provideCredentialManager(
@ApplicationContext context: Context,
): CredentialManager {
return CredentialManager.create(context)
}
}
@Inject
lateinit var credentialManager: CredentialManager
fun requestGoogleLogin(context: Context) {
viewModelScope.launch {
runCatching {
credentialManager.getCredential(
request = credentialRequest,
context = context,
)
}
```
}
}
결과
🚨메모리 leak 발생!
그러나 화면 회전과 같은 구성 변경 시 액티비티가 onDestroy 가 일어나지만, 뷰 모델은 액티비티보다 생명주기가 길기때문에 유지된다.따라서 뷰 모델이 액티비티의 context를 받아와서 사용할 경우 잘못된 context를 사용하게 된다.
➡️ 4. GoogleAuthModule을 @SingletonComponent로 지정하고 provideCredentialManager를 @Singleton으로 만들어준 후 context를 @ApplicationContext로 지정해줄 경우
@Provides
@Singleton
fun provideCredentialManager(
@ApplicationContext context: Context,
): CredentialManager {
return CredentialManager.create(context)
}
결과
모든 경우에서 메모리 누수가 발생하였다.
즉 뷰 모델에서 액티비티의 컨텍스트를 참조하는 경우 액티비티 구성 변경 시 액티비티가 소멸되기 때문에 생명주기가 다르고 메모리 누수가 발생한다.
해결
미해결
참고
https://www.charlezz.com/?p=44748
https://www.charlezz.com/?p=44580
'🐤2024 안드로이드 > 🍿 영화 프로젝트 개발 일지' 카테고리의 다른 글
Android 레이아웃 공식문서 정리 (2) | 2024.03.27 |
---|---|
Android : 초기화 로직을 담는 "App StartUp 라이브러리" 알아보기 (0) | 2024.03.26 |
🏛️[Android 앱 아키텍쳐] : UI layer , Domain layer, Data layer (0) | 2024.03.15 |
💉Android 로그인 기능에 di 적용해보는 기록 (0) | 2024.03.15 |
🫙Android 로그인 토큰 저장 : Proto Datastore 적용하기 (0) | 2024.03.15 |