Manifest Android Interview: 질문으로 학습하는 안드로이드 (3)

seunghee song·2025년 11월 9일

31. 애플리케이션 용량을 어떻게 줄이나요?

  1. 사용하지 않는 리소스 제거

    • Lint라는 도구로 불필요한 레이아웃, 이미지, 문자열 리소스 식별하는데 도움을 준다.
      android {
      	buildTypes {
      			release {
      				shrinkResources true //빌드 프로세스중 미사용 리소스 자동 제거
      			}
      		}
      }
    1. R8로 코드 축소 활성화

      (R8: 앱의 크기를 줄이고, 성능을 최적화하며, 코드를 난독화하는 데 사용되는 컴파일러)

      • 미사용 클래스, 메서드 제거하고 코드 난독화해서 경량화 한다.
      • ProGuard 설정시 중요 코드나 리플렉션 기반 라이브러리 난독화 생략하고 오동작 하지 않도록 보장
    2. 리소스 최적화

      • Vector drawable로 대체시 한 개의 XML만으로 모든 해상도에 대응할 수 있다.
      • 이미지 압축: TinyPNG, ImageMagick 도구 활용
      • webP형식으로 변환
  2. AAB 사용

  • AAB 전환시 Google Play가 개별 기기에 맞는 최적화된 APK 제공 가능 특정 구성에 필요한 리소스, 코드만 포함해 앱 용량 줄인다.
  1. 불필요한 의존성 제거

    • 프로젝트 의존성 검토하고 중복되거나 불필요한 라이브러리 제거
  2. 네이티브 라이브러리 최적화

    미사용 아키텍처 제외 , 디버그 심볼 제거

  3. Proguard 규칙 구성하여 디버그 정보 줄이기

    디버깅 메타데이터는 최종 apk나 AAB에 불필요한 무게를 더하기에 proguard-rules.pro 파일 구성해 이 정보 제거

  4. 동적 기능 사용

    • 앱의 특정 기능과 리소스를 분리하여 앱 번들에 포함시키는 기능
    • 앱 전체를 다운로드하지 않고도 필요한 기능만 사용자가 다운로드하여 실행할 수 있어 초기 설치 APK 사이즈를 줄여준다.
    • 특정 기능을 나중에 다운로드할 수 있도록 설정하여 사용자 경험을 개선하고 빌드 시간을 단축하는 데 유용

32. 안드로이드 애플리케이션의 프로세스(process)란 무엇이며, 안드로이드 운영 체제는 이를 어떻게 관리하나요?

프로세스란?

애플리케이션이 실행되는 환경, 단일 실행 스레드로 작동

  • 안드로이드에서 프로세스 작동 방식
    • 애플리케이션 시작시 운영체제는 리눅스 fork() 시스템 함수 호출해 해당 앱을 위한 새 프로세스 생성
    • 각 프로세스는 Dalvik 또는 ART 가상 머신의 고유 인스턴스에서 실행되어 안전하고 독립적인 실행 보장
  • 애플리케이션 컴포넌트와 프로세스 연결
    • 모든 컴포넌트 동일 프로세스 내에서 실행
    • Manifest.xml에서 android:process 속성 사용해 프로세스 할당 커스텀 가능
    • 필요시 우선순위가 낮은 프로세스 종료
  • 프로세스와 앱 생명주기
    • 앱 현 상태 기반으로 프로세스 및 앱 생명 주기 관리하며 엄격한 우선순위 계층을 따른다
    1. 포그라운드 프로세스(Foreground Process): 사용자와 활발하게 상호 작용하며 실행 중인 프로세스입니다. 가장 높은 우선순위의 프로세스이며 거의 종료되지 않습니다.
    2. 보이는 프로세스(Visible Process): 사용자에게 보이지만 활발하게 상호 작용하지 않는 프로세스입니다(가령, 다이얼로그 뒤의 Activity).
    3. 서비스 프로세스(Service Process): 데이터 동기화나 음악 재생과 같은 작업을 수행하는 백그라운드 Service를 실행하는 프로세스입니다.
    4. 캐시된 프로세스(Cached Process): 더 빠른 재실행을 위해 메모리에 유지되는 유휴 프로세스입니다. 캐시된 프로세스는 우선순위가 가장 낮고 메모리가 부족할 때 가장 먼저 종료됩니다.

실전 질문

Q) 서로 다른 안드로이드 컴포넌트들을 별도의 프로세스에서 실행해야 하는 애플리케이션을 개발 중이라고 해봅시다. AndroidManifest에서 이를 어떻게 구성하며 여러 프로세스를 사용할 때의 잠재적인 단점은 무엇인가요?

manifest파일의 android:process 속성으로 프로세스 할당 커스텀할 수 있다.
단점은 프로세스마다 힙이 할당되기에 메모리 사용량이 늘고 오버헤드와 직렬화 비용이 커진다. 또한 프로세스 시작과 디버깅 난이도 증가 ANR 리스크도 고려해야 한다.

Q) 중요한 프로세스가 종료되는 것을 방지하기 위해 개발자가 따라야 할 전략은 무엇인지 설명해 주세요.

꼭 필요한 작업만 Foreground Service로 실행하고 불필요한 백그라운드 서비스는 지양해야 한다. 또한 안드로이드에서 권장하는 WorkManager와 JobScheduler를 이용해서 백그라운드 작업을 수행해야 한다.

Q) Activities, Services, Broadcast Receivers, Content
Providers가 안드로이드의 4대 주요 컴포넌트라고 불리는 이유는 무엇인가요?

4개의 컴포넌트는 모두 안드로이드 애플리케이션이 시스템 및 다른 애플리케이션과 상호작용할 수 있도록 하는 필수 구성요소이기 때문이다. 앱의 생명주기 관리하고 동작 정의하며 프로세스간 통신을 가능하게 하여 안드로이드 프로세스와 앱의 생명주기 모델과 밀접히 관련되게 한다.

0. Jetpack Compose의 동작 구조는 어떻게 이루어져 있나요?

  • Compose의 구조
    • Compose Compiler / Compose Runtime / Compose UI

    • Compose Compiler:

      • kotlin으로 작성된 선언적 ui코드를 jetpack compose가 실행할 수 있는 최적화된 코드로 변환하는 역할
      • 컴파일러는 컴파일 타임에 정적 코드에 대해 더 자세히 접근 가능하며 kotlin 소스 코드 동적으로 변환하고 최적화된 java 바이트 코드 생성 가능
      • @Composable 과 같은 어노테이션은 코드 생성, recomposition 관리 및 성능 최적화와 같은 작업을 조율하는 컴파일러의 내부 매커니즘을 통해 작동
    • Compose Runtime

      • recomposition 및 상태 관리 지원하는데 핵심 기능 제공
      • 변경 가능 상태 처리, 스냅샷 관리, 앱 상태 변경시마다 ui 업데이트 트리거
      • gap buffer 자료구조 사용. 컴포지션 상태 memoizing 하는 방식으로 작동
      • 반응형 ui 구축을 위해 필수적인 작업 수행 (side - effect 관리,/remember를 통한 상태 보존 / 상태 변경시 recomposition 트리거/CompositionLocal을 사용해 컨텍스트별 데이터 저장/ui계층구조 효율적으로 생성위한 compose 레이아웃 노드 구축)
      • 한계
        • Gap buffer는 임의 접근(random access) 과 노드 재배열에 비효율적
        • Compose에서는 매 recomposition마다 일부 노드 이동, 삽입, 삭제가 자주 일어나기 때문에 이 부분에서 비용이 커질 수 있다.
        • 즉, UI 트리(Composition Tree) 규모가 커질수록 SlotWriter / SlotReader 연산 비용이 누적되는 문제.
      • 이에 따라 link table 자료구조로 마이그레이션 진행중 → 효율적인 삽입,삭제 재배열 가능
    • Compose UI
      - Compose Runtime에 의해 처리되는 Compose 레이아웃 트리 구축을 단순화하도록 설계된 광범위한 컴포넌트 제공

      Q) Compose Compiler의 역할은 무엇이고, KAPT 또는 KSP와 같은 전통적인 어노테이션 프로세서와 어떻게 다른가요?

      kotlin으로 작성된 선언적 ui코드를 jetpack compose가 실행할 수 있는 최적화된 코드로 변환하는 역할이다.

      구분Compose CompilerKAPT / KSP
      종류Kotlin Compiler PluginAnnotation Processor
      동작 시점Kotlin 컴파일 단계 중 IR (Intermediate Representation) 변환 단계Kotlin → Java AST 변환 이후 별도 프로세스에서 수행
      목적@Composable 함수 분석 및 Recomposition 코드 생성어노테이션 기반 코드 생성 (예: Room, Hilt, Glide)
      출력물기존 함수 내에 Slot 관리 로직 삽입별도의 .java / .kt 소스 생성
      성능컴파일러 내부 최적화로 빠름AST 파싱 기반이라 비교적 느림
      대표 예시remember { ... } → 상태 슬롯 저장 코드 삽입@Entity, @Dao → 코드 생성

      Q) Compose Runtime은 recomposition과 상태를 어떻게 관리하며, 내부적으로 어떤 자료구조를 사용하나요?

      Compose runtime은 앱의 상태 변화 감지하고 변경된 부분만 효율적으로 다시 그리는 recompose 역할을 수행한다. 이를 위해 내부적으로 slottable이라는 자료구조 사용

1. Compose 페이즈(phase)에 대해 설명해 주세요

Compose 그려지는 과정

  1. Composition
    1. Composable 함수를 실행하고 UI트리 구축
    2. Slot Table 데이터 구조에 컴포저블간 관계 기록 (Slot Table: 컴포지션 단계 중 UI컴포넌트 상태 저장하고 관리하기 위해 Compose에서 사용되는 자료구조 / 상태 변경에 영향을 받는 요소만 업데이트)
    3. 필요한 경우 다시 recomposition을 트리거
  2. Layout
    1. 제공된 제약 조건에 따라 UI 컴포넌트의 크기와 위치 결정
  3. Drawing
    1. UI컴포넌트가 화면위에 렌더링되는 절차
    2. Skia 그래픽 엔진 사용

결론: Jetpack Compose의 3단계로 이루어져 렌더링이 진행된다. Composition 단계에 UI 트리 구축하고 Layout 단계는 컴포넌트를 정렬하며 Drawing 단계는 시각적으로 렌더링을 한다.

2. Jetpack Compose가 선언적(declarative) UI 프레임워크라고 불리는 이유는 무엇인가요?

왜 Jetpack Compose는 선언적 UI프레임워크인가?

Compose는 특정 상태에서 UI가 어떻게 보여야 하는지 설명하는 선언적 UI프레임워크 특성이 있다.

어떤 선언적 UI의 특징을 가지고 있는가?

  • 상태 주도
    • 선언적 UI프레임워크는 상태 관리 시스템이 라이브러리 자체에 내장됨. 상태가 변경될때마다 프레임워크는 recomposition을 트리거하여 영향을 받는 컴포넌트만 업데이트하고 최신 데이터 반영해 뷰를 수동적으로 관리할 필요 없도록 한다.
    • 컴포넌트를 함수 또는 클래스로 정의 이 또한 선언적 UI의 특성중 하나. UI컴포넌트를 모듈식 컴포넌트로 정의하도록 한다. 각 함수는 현재 상태를 기반으로 UI를 설명하고 다른 함수와 결합하여 모듈식이며 확장가능한 구조를 만들 수 있다.
    • 직접적 데이터바인딩: 직접 데이터를 UI컴포넌트에 직접 바인딩해 수동적으로 데이터 동기화하는 수고를 덜 수 있다. 접근 방식 더 깔끔하고 유지 관리하기 쉬운 코드 만든다.
    • 컴포넌트 멱등성: 컴포넌트 호출횟수에 관계없이 동일한 입력에 대해 동일한 출력 생성. 컴포넌트의 일관된 동작과 재사용성 보장. 이에 따라서 동일한 UI 결과 도출을 위해 예측 가능하고 안정적인 UI 렌더링을 가능하게 한다.

결론

UI가 무엇을 표시해야 하는지 알아야 표현할 수 있기 때문에 Jetpack Compose는 선언적 UI 라고 할 수 있다. recomposition을 통해 UI가 어떻게 업데이트 하는지에 대해 Compose Runtime이 자동으로 처리해 개발자는 UI 업데이트에 대해서는 신경쓰지 않아도 되어 유지 보수 쉬운 코드를 만든다.

profile
안드로이드 개발자

0개의 댓글