본문 바로가기
Android/안드로이드 프로그래밍 Next Step

[Next Step] 5. Activity 구성 변경 (Configuration)

by Diane_KIM 2023. 8. 28.

Configuration : 컴포넌트에서 어떤 리소스를 사용할지 결정하는 조건, 이 조건은 FW에서 정해져 있음

android.content.res.Configuration 멤버변수 

- densityDpi, fontScale, keyboard, locale, orientation, screenLayout... 17개

- fontScale, local은 단말의 환경 설정에서 정할 수 있는 사용자 옵션, 나머지는 단말 현재 상태

 

리소스 반영

  • 언어나 화면회전 같은 리소스 변경은 액티비티 재시작해서 새로운 리소스로 적용되는 방식을 사용 (액티비티 외의 다른 컴포넌트는 구성이 변경되어도 재시작X)
  • 구성변경에 의해 액티비티 재시작되면, 하나의 인스턴스를 가지고 새로 초기화해서 재사용하는 것이 아니다. 기존 인스턴스는 onDestory까지 실행하고, 새로운 인스턴스가 onCreate 부터 실행

메모리 누수 가능성 있는 경우

  1. Activity 목록 참조 : Activity인스턴스를 컬렉션에 모아두고, 액티비티가 종료할 때 제거해야하는데 실수로 빠뜨렸을 때
  2. Activity의 내부 클래스나 인명 클래스 인스턴스가 Activity 에 참조를 갖고 있고, 인스턴스를 외부에 리스너로 등록한 경우에 해제하지 않으면 발생. (내부 클래스에서 XXActivity.this 를 쓸 수 있으면 Activity 에 대한 참조를 가지고 있는것)                                       => 권장 방법 : 단순 내부 클래스는 정적 내부 클래스로 생성
  3. 싱글톤에서 Context가 아닌 Activity 전달시 참조가 남아 문제 발생
  4. AsyncTask에서 Activity 참조 : AsyncTask가 오래 걸리면 OOM 발생 가능성 있음

* 구성변경시 프레임워크 동작 : system_server에서 동작하는 ActivityManagerService에서 앱 프로세스의 메인 클래스인 ActivityThread에 새로운 Configuration을 전달한다

* Configuration은 한순간에 1개의 값만 존재한다

 

태스크 : 액티비티 작업 묶음 단위

예를들어, 사진 리스트를 보고, 상세를 살펴보고, 사진을 올리려고 카메라를 실행시키는 행위를 할때 보여지는 3개의 액티비티가 하나의 태스크가 되는데, 2개의 앱이 하나의 태스크가 된다.

 

* taskAffinity : Activity 실행 시 신규 task 를 만들 경우 어느 task 에 속할지 지정하는 것. (디폴트로 앱의 패키지명이 설정됨)

 

태스크 속성을 부여하는 2가지 방법 

1. 호출자에서 '너를'이렇게 다루겠어'

2. 피호출자에서 '나를 이런식으로 취급해줘'

 

1번째 호출자가 피호출자에게 속성을 부여하려면 Intent 플래그에 지정

  • Intent에 setFlag(int flags) 파라미터에 or 연산(|)으로 여러개를 전달 가능
  • Intent 플래그에 전달하는 값은 피호출자의 launchMode보다 우선해서 적용된다.
  • 많이 쓰는 플래그들
    • FLAG_ACTIVITY_SINGLE_TOP : singleTop launchMode와 동일한 효과
    • FLAG_ACTIVITY_NEW_TASK : singleTask launchMode와 동일한 효과
    • FLAG_ACTIVITY_CLEAR_TOP : 스택에서 피호출자보다 위에 있는 액티비티를 종료시킨다. (스택 A, B, C 에서 C에서 이 플래그 이용해 B를 시작하면 A, B만 스택에 남는다)
    • FLAG_ACTIVITY_CLEAR_TASK : 피호출자가 시작되기 전에 관련된 스택이 모두 제거된다. 이 플래그는 FLAG_ACTIVITY_NEW_TASK와 함께 사용되어야 한다. (로그아웃하고, 다른 아이디로 로그인할때 태스크를 정리하고 메인 엑티비티를 새로 시작할때 사용)
    • FLAG_ACTIVITY_REORDER_TO_FRONT : 스택에 동일한 액티비티가 이미 있으면 그 액티비티를 스택의 맨 위로 올린다. (FLAG_ACTIVITY_CLEAR_TOP 플래그와 함께 사용하면 옵션이 무시됨, 호출자가 액티비티일 때만 정상적으로 재배치 동작)

 

2번째 피호출자에서 속성을 부여하는 방법은 액티비티 선언에 android:launchMode로 지정

  • launchMode 는 standard, singleTop, singleTask, singleInstance
  • singleTask와 singleInstance는 1개의 인스턴스만 존재
  • standard : 기본값, 매번 새로운 액티비티 인스턴스를 생성해서 Intent 전달
  • singleTop : 호출하고자 하는 액티비티가 이미 topActivity에 있다면 새로 생성하지 않고 onNewIntent()로 Intent 전달. (top에 없으면 standard와 동일하게 동작)
  • singleTask : 태스크에 이미 동일한 액티비티의 인스턴스가 있으면, 새로 생성하지 않고 onNewIntent()로 전달. top에 없으면 새로운 태스크를 만들고 액티비티는 새로운 태스크의 baseActivity가 된다. 
    • 예로 B가 singleTask고, A->B->C 호출에서 B를 호출할때 C는 스택에서 제거가 되고 A->B 의 onNewIntent() 호출됨
  • singleInstance : 태스크에 들어가는 액티비티가 하나밖에 없는 것.
    • 예로 A3가 singleInstance고, A1->A2->A3->A4 호출하면 A3는 별도의 태스크가 되므로 [A1,A2,A2], [A3] 2개의 태스크로 된다.

 

<activity-alias> 선언

제거된 액티비티 대체

- SplashActivity를 더이상 사용하지 않고 MainActivity로 보여주기로 했는데, 기존에 설치한 숏컷이나 링크가 남아있는 경우 

<activity-alias
	android:name=".SplashActivity"
    android:targetActivity=".MainActivity"/>

 

FLAG_ACTIVITY_CLEAR_TOP 한계 해결

스택에 [A,B,A,B] 액티비티가 있을때 B에서 FLAG_ACTIVITY_CLEAR_TOP 플래그를 전달해서 A를 시작하면, [A,B,A] 로 남는다.

이때 [A] 만 남게 할 수 있는 방법은 A에 별명을 지어주고 첫번째 액티비티 A가 시작할때는 별명(FirstA)으로 시작하는것.

그럼 스택에는 [FirstA,B,A,B] 가 있고, 다음과 같이 Component 클래스에 별명을 전달해서 액티비티를 시작

Intent intent = new Intent().setComponent(
	new Component(this, "com.suribada.someapp.FirstActivityA"));
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP 
	| Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);