Hilt에서 Application Context와 Activity Context

이윤진·2024년 8월 6일
0

Android 개발

목록 보기
12/13

Mental-AI (GitHub) 라는 애플리케이션을 개발하다가 발생한 에러를 바탕으로 context 이야기를 해보려 합니다.

Hilt의 @ApplicationContext 어노테이션을 활용하여 viewModel에서 finish 함수를 개발하려고 하다가 발생했습니다.

코드는 다음과 같습니다.

class LoginViewModel @Inject constuctor (
	@ApplicationContext private val context : Context
) : ViewModel(){
	fun finish(){
    	(context as activity)?.finish
    }
}

java.lang.classcastexception: yj.mentalai.di.application cannot be cast to android.app.activity when use context as activity

activity로 변환할 수 없는 context를 activity로 변환하려고 했기 때문에 발생한 에러였습니다.
저는 @ApplicationContext를 사용하여 context를 가져왔기 때문에 제가 가지고 있는 context는 application 수준의 context입니다. 여기에서 activity를 가져오려고 했기 때문에 에러가 발생한 것입니다.

context : 현재 사용되고 있는 Application 또는 Activity에 대한 포괄적인 정보를 지니고 있는 객체

Application Context?

: application lifecycle을 따르며 애플리케이션이 실행되어 종료될 때까지 동일한 객체 참조

Activity Context?

: activity lifecycle을 따르며 onDestroy() 될 때 사라짐

이 문제를 해결하기 위해 @ActivityContext 어노테이션을 사용하려고 했지만, 이번엔 @Provides-annotated 가 없다고 에러가 났습니다.

@ActivityContext를 사용하기 위해서는 ActivityComponent에 설치된 모듈에서 @ActivityContext를 제공하도록 설정해야 했습니다.

그러나 내용을 찾던 도중, 안드로이드 개발시 Activity Context보다 Application Context를 사용하는 것이 더 권장된다는 글을 보았습니다.

그 이유는 다음과 같습니다.

  • 이유1 - 수명주기
    Application Context의 수명이 더 길다.
    Activity Context는 Activity의 수명주기에 종속되기 때문에 destroy 되면 해당 context도 사라짐
  • 이유2 - 메모리 누수 방지
    Application Context는 Application 생명주기 동안 유지되기 때문에 잘못 사용하더라도 메모리 누수 발생 가능성이 낮다.
    Activity Context는 부적절하게 사용하면 메모리 누수가 발생할 수 있다.
    context를 사용하는 객체가 만약 장기간 유지되는 작업이면, activity가 먼저 끝나 context가 사라질 수도 있다.

그러나 반드시 Activity Context를 사용해야 하는 경우도 있습니다.
UI와 밀접한 관련이 있는 작업들은 Activity Context를 사용해야 합니다. 예를 들어 Toast와 같은 작업은 Activity Context가 필요합니다.

왜 FLAG_ACTIVITY_NEW_TASK를 써야 할까?

화면 이동을 할 때 우리는 intent를 사용합니다. 그리고 그 intent에는 context를 파라미터로 보내줍니다. 이때 ApplicationContext를 사용하여 넘겨주면, FLAG_ACTIVITY_NEW_TASK가 필요하다며 에러가 발생합니다.

FLAG_ACTIVITY_NEW_TASK : 새로운 task를 생성하여 그 task 안에 activity를 추가할 때 사용. 기존에 사용하던 task들 중에 생성하려는 Activity와 동일한 Affinity를 가지고 있는 task가 있다면 그 곳으로 Activity가 들어감.

  • Task - stack 구조로 되어 있으며, 애플리케이션에서 실행되는 activity를 보관하고 관리하는 역할 담당

왜 해당 flag를 사용해야 할까요?

android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

발생된 에러에 따르면 Activity context 밖에서 startActivity 함수를 사용했기 때문이라고 합니다.

  • back stack - 새로운 activity를 시작하면 stack에 쌓이고, 뒤로 가기 버튼을 누르면 stack에서 제거되며 이전 activity로 돌아감

activity context는 현재 task와 back stack에 대한 정보를 알고 있으며, 새로운 activity를 같은 task 내에서 시작할 수 있습니다.

그러나 우리는 application context를 사용합니다. application context는 특정 task나 back stack에 대한 정보가 없습니다. 따라서 application context는 어느 task에서 시작해야 할 지 없기 때문에 시스템에서 오류를 발생 시킵니다.

따라서 새로운 task에서 activity를 시작하겠다고 명시적으로 알려줘야 합니다.

이것이 Application Contex에서 FLAG_ACTIVITY_NEW_TASK를 반드시 사용해야 하는 이유입니다.

profile
Android/Flutter 개발

0개의 댓글