영어 데일리

안드로이드 인터뷰 질문과 답변 기본 (25.01.23)

현욱 정리장 2025. 1. 23. 16:12

https://medium.com/@anandgaur2207/scenario-based-android-interview-questions-and-answers-e1b1edc78c02

 

Scenario Based Android Interview Questions and Answers

Scenario-based questions are commonly asked in Android interviews to test a candidate’s problem-solving ability, technical knowledge, and…

medium.com

시나리오 기반 질문은 일반적인 안드로이드 인터뷰 질문입니다. 

후보자의 문제 해결 능력, 기술 지식, 실제 상황에서 대응력을 평가하기위해 자주사용됩니다

이 블로그에서는 일반적인 시나리오 기반 인터뷰 질문을 설명하고, 그들의 답변, 그리고 안드로이드 인터뷰를 미리 준비할수있게 도와주려고합니다.

 

1. 부드러운 스크롤링을 리사이클러뷰에서 사용하기 위해 큰 데이터 셋을 어떻게 관리하는게 효율적인가요? 

  • 시나리오

앱에 recyclerview를 사용해서 1천개의 아이템을 디스플레이 해줘야합니다. 유저가 스크롤할때에 렉이 걸린다고 보고합니다. 성능을 어떻게 향상 시킬 수있을까요?

  • 답변

1. View 재활용 옵션을 활성화합니다..

recyclerview는 각 항목마다 새 뷰를 생성하지 않게 하기위해 뷰를 재사용합니다.

recyclerView.setHasFixedSize(true)


2. DiffUtil 최적화 하기

DiffUtil의 사용은 전체 리스트 리로딩 대신에 수정된 아이템만 업데이트 하게 해줍니다.

val diffCallback = MyDiffCallback(oldList, newList)
val diffResult = DiffUtil.calculateDiff(diffCallback)
diffResult.dispatchUpdatesTo(adapter)


3. 페이징 라이브러리 사용

큰 데이터셋일 경우에는, 페이징 라이브러릴 구현하여 로딩을 늦추는것도 좋습니다.

val pagingSource = MyPagingSource()
val pager = Pager(PagingConfig(pageSize = 20)) { pagingSource }.flow


4. 이미지 로딩 최적화

coil 또는 glide와 같은 효율적인 라이브러리들 사용하고, 플레이스홀더와 캐싱 메커니즘을 활용하세요. 

 

 

2. 안드로이드 앱에서 설정 변경같은건 어떻게 관리하나요? 

  • 시나리오

화면 전환으로 인해 앱이 중지가 발생할 때에 너는 화면전환, 언어 업데이트와 같은 설정 변경 처리를 어떻게 핸들링하나요? 

  • 답변

1. ViewModel 사용

구성 변경 시 데이터를 유지하기 위해 UI 와 관련된 데이터를 ViewModel에 저장합니다.

class MyViewModel : ViewModel() {
    val userName = MutableLiveData<String>()
}

 

2. onSaveInstanceState

onSaveInstanceState에 일시적인 데이터를 저장하고, onCreate에서 불러오세요.

override fun onSaveInstanceState(outState: Bundle) {
    outState.putString("USER_NAME", userName)
    super.onSaveInstanceState(outState)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val name = savedInstanceState?.getString("USER_NAME")
}


3. Activity 재 생성 피하기 

화면 회전과 같은 특정 시나리오를 수동으로 처리하기위해 manifest에 android:configChanges를 사용하세요.

<activity
    android:name=".MainActivity"
    android:configChanges="orientation|screenSize" />



3. 너의 앱에 오프라인 동기화  데이터를 구현하는 방법 

  • 시나리오

유저가 오프라인 상태일때도 작업이 가능하게 하는 개발이 필요합니다. 그리고 네트워크가 이용가능할때에 데이터를 자동으로 동기화해줘야합니다.

  • 답변

1. Room 데이터베이스 이용

Room을 사용해 데이터를 로컬에 저장합니다.

@Entity(tableName = "tasks")
data class Task(val id: Int, val description: String, val isSynced: Boolean)


2. WorkManager

데이터 동기화를 위해 백그라운드 작업을 스케쥴화 합니다. 

val workRequest = OneTimeWorkRequestBuilder<SyncWorker>().build()
WorkManager.getInstance(context).enqueue(workRequest)


3. 네트워크 연결을 체크합니다.

ConnectivityManager를 사용해서 네트워크 변경을 모니터링합니다.

val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val isConnected = connectivityManager.activeNetwork != null

 

4. 적절한 보안 조치를 이용해 로그인 스크린을 디자인하는 법 

  • 시나리오

민감한 유저 정보를 처리해야하는 로그인 화면 설계를 해야하는 작업이 있습니다. 

  • 답변

1. Encrpyted SharedPreferences를 사용합니다. 

사용자 자격증명을 안전하게 저장하세요

val sharedPreferences = EncryptedSharedPreferences.create(
    "secure_prefs",
    MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
    context,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

 

2. Https를 사용하세요

통신은 https를 이용한 보안 채널에서 사용하세요. 

 

3. 인증된 토큰 기반 사용

사용자 자격증명을 저장하는 대신 Oauth token을 사용하세요.

 

4. 로그인 시도 횟수 제한 

brute force 공격을 막기위해 제한을 구현하세요.

 

5. 유저 액티비티 비 활성화 감지를 구현하는 방법 

  • 시나리오

보안 이유로 인해 5분이상 비활성화될 경우 유저를 로그아웃시키는걸 구현하고 싶습니다.

  • 답변

1. Foreground Service

유저 인터렉션을 트래킹하고 인터렉션이 감지되지 않을 경우 타이머를 시작하세요.

 

2. 생명주기 옵저빙

LifecycleObserver를 사용해 백그라운드와 포그라운드 상태에서 감지하세요.

class AppLifecycleObserver : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun onAppBackgrounded() {
        // Start inactivity timer
    }
}

 

3. Broadcast receivers

유저 액션 (키 클릭과같은)을 감지하고 타이머를 초기화하세요.

 

6. 안드로이드 앱에서 메모리릭을 처리하는 방법

  • 시나리오

장기적인 사용때문에 OutofMemoryError가 발생하여 앱이 죽었습니다. 어떻게 디버깅하고 메모리릭을 방지할 수 있나요?

  • 답변

1. Context Leaks 피하기

오래 살아야 하는 컴포넌트에서는 activity 또는 fragment context 대신에 applicationcontext를 사용합니다. 

 

2. WeakReferences 사용

무거운 객체에 대해 강한 참조를 방지하세요

private val myHandler = Handler(Looper.getMainLooper(), WeakReferenceHandler(this))


3. LeakCanary  tkdyd

메모리릭을 감지할 수 있는 LeakCanary 통합

implementation "com.squareup.leakcanary:leakcanary-android:2.x"



7. 앱 디버깅할 동안 민감한 데이터 노출을 막는 방법 

  • 시나리오

은행앱을 개발하면서 민감한 정보가 APK를 디컴파일하거나 로그를 검사할 때 노출되지 않도록 해야합니다 

 

  • 답변

1. Proguard/R8 난독화

Proguard와 R8을 사용해 코드를 난독화하세요

minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'


2. 민감 데이터 로깅을 피하세요.

민감 정보는 프로덕션 빌드에 로깅하지 않도록 보장하세요.

if (BuildConfig.DEBUG) {
    Log.d("DEBUG", "Debug mode enabled")
}

 

3. SharedPreferences 암호화

민감 데이터 보안 저장 시 EncrpytedSharedPreferences사용

 

4. 네트워크 암호화

모든 네트워크 통신에 Https 사용

 

8. 서로 의존하는 여러 API 호출을 어떻게 처리할것인가요?

  • 시나리오

3개의 API콜을 순차적으로 해야합니다. 각각의 콜은 이전의 결과에 의존합니다.

  • 답변

1. 코루틴 사용

코루틴 사용은 API Call을 순차적으로 하게 해줍니다. 

viewModelScope.launch {
    val user = apiService.getUser()
    val orders = apiService.getOrders(user.id)
    val details = apiService.getOrderDetails(orders[0].id)
}


2. RxJava 사용

flatMap의 사용은 API Calls을 결합해줍니다.

apiService.getUser()
    .flatMap { user -> apiService.getOrders(user.id) }
    .flatMap { orders -> apiService.getOrderDetails(orders[0].id) }
    .subscribe()



3. 에러 핸들링

try-catch 블록과 onErrorResumeNext 와 같은 오퍼레이터 사용은 적절한 에러 핸들링을 보장하게 해줍니다. 

 

9. 안드로이드 앱에서 API Key를 안전하게 보호하는방법

  • 시나리오

써드 파티 서비스를 허용하기 위해 API Key를 사용합니다. 그리고 인증되지않은 접근을 막아야합니다.

 

  • 답변

1. BuildConfig 로 APi Key 이동

build.gradle 파일에 키들을 저장하세요 

buildConfigField "String", "API_KEY", "\"YOUR_API_KEY\""


2. NDK 사용

네이티브 코드에 키 저장은 안드로이드 NDK의 사용하세요.

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_MainActivity_getApiKey(JNIEnv *env, jobject) {
    return env->NewStringUTF("YOUR_API_KEY");
}


3. 백엔드 프록시 보안

API 요청을 서버를 통해 프록시 처리하여 키 노출을 방지하세요.

 

10. 싱글 액티비티 앱에서 백스택을 관리하는방법

  • 시나리오

여러 fragments가 사용된 싱글액티비티 앱을 사용하고 있습니다. 그리고 유저가 백버튼 네비게이션에 대해 이슈를 리포트했습니다.

 

  • 답변

1. FragmentManager

FragmentManager를 사용해서 추가되는 fragments에 대해 백스택을 관리하세요

supportFragmentManager.beginTransaction()
    .replace(R.id.container, DetailFragment())
    .addToBackStack(null)
    .commit()


2. 백 처리 커스텀

onBackPressed를 오버라이드해서 네비게이션 로직을 커스텀화하세요.

override fun onBackPressed() {
    if (supportFragmentManager.backStackEntryCount > 0) {
        supportFragmentManager.popBackStack()
    } else {
        super.onBackPressed()
    }
}


3. 네비게이션 컴포넌트 사용

네비게이션 컴포넌트 사용은 백스택 관리에 매우 좋습니다.

<fragment
    android:id="@+id/homeFragment"
    android:name="com.example.HomeFragment" />



11. 앱을 낮은 메모리 상황이나 느린 네트워크 같은 엣지 케이스에 대해 어떻게 테스트하시겠습니까?

  • 시나리오

낮은 메모리 상황 또는 느린 네트워크 시나리오에서 앱이 중지가 발생합니다

  • 답변

1. 메모리 테스트

안드로이드 스튜디오 프로파일러를 사용해서 느린 메모리 환경 시뮬레이트

 

2. 네트워크 쓰로틀링

charles proxy 나 android studio 네트워크 프로파일러와 같은 툴을 이용해 느린 네트워크를 시뮬레이트

 

3. 오프라인 테스트

네트워크가 끊겼을때 앱이 어떻게 동작하는지 테스트

 

12. 프로덕션 상황에서 앱이 죽었을때 처리 

  • 시나리오

프로덕션 환경에서 앱이 죽었습니다. 하지만 유저는 특정한 설명 없이 일반적인 에러 메세지만 발생되었다고 리포트 해주고 있습니다.

  • 답변

1. 크래시 리포팅 툴 

크래시틱스나 센트리와 같은 크래시 트랙 툴 통합

implementation 'com.google.firebase:firebase-crashlytics:18.3.3'

 

2. 커스텀 에러 핸들링

글로벌 단에서 사용할 수 있는정의되지 않은 에러캐치 

Thread.setDefaultUncaughtExceptionHandler

Thread.setDefaultUncaughtExceptionHandler { thread, exception ->
    Log.e("AppCrash", "Uncaught exception: ${exception.message}")
}



3.. 프로가드 매핑

크래시틱스와 같은 툴에 프로가드 매핑 파일을 업로드 하여 스택 트레이스 디코딩

 

4. 유저 피드백

자세한 로그를 앱에서 바로 전송할 수 있게 유저 리포팅 이슈 기능 구현

 

13. 앱에 큰 파일을 올리기 위한 처리

  • 시나리오

앱이 큰 파일을 올리기 위한 작업이 필요합니다. 하지만 유저는 느린 네트워크 상황에서 타임아웃 에러가 난다고 리포팅해주고 있습니다.

  • 답변

1. 청크 업로드

큰 파일을 작은 청크 단위로 나누고, 순차적으로 전송합니다.

fun uploadChunk(chunk: ByteArray) { /* Upload logic */ }



2. 백그라운드 작업으로 대체

Workmanager를 사용해 오래 걸리는 업로드 작업에 대한 응답을 보장합니다.

val uploadRequest = OneTimeWorkRequestBuilder<UploadWorker>().build()
WorkManager.getInstance(context).enqueue(uploadRequest)



3. 재시도 로직 

기하급수적인 업로드 재시도 실패 방지 로직 구현

setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, TimeUnit.SECONDS)



4. 업데이트 상태 표시

notification을 사용해 업데이트 상태를 보여주세요.

notificationManager.notify(notificationId, builder.build())



14.전환할 동안 부드러운 에니메이션을 보장하는 방법

  • 시나리오

복잡한 애니메이션이 포함되어있습니다. 하지만 유저는 오래된 디바이스에서 셔틀링이 발생한다고 합니다.

  • 답변

1. 모션 레이아웃 사용

MotionLayout을 사용해 부드러운 전환을 생성하세요

<MotionScene>
    <Transition
        app:constraintSetStart="@id/start"
        app:constraintSetEnd="@id/end"
        app:duration="1000" />
</MotionScene>



2. Drawable 리소스 최적화

레스터 이미지 대신에 Vector 드로어블 사용

 

3. 프레임 레이트 테스트

안드로이드 스튜디오 프로파일러를 사용하여 애니메이션들이 60fps에서 실행되는지 확인하세요.

 

15. 배터리를 고갈시키지 않고 백그라운드 작업을 처리하는 방법 

  • 시나리오

배터리 소모에 영향을 주지 않으면서 주기적인 백그라운드 작업을 진행해야합니다.

  • 답변

1. 네트워크 유형 또는 충전 상태와 같은 제약 조건을 가진 백그라운드 작업을 예약하세요.

val workRequest = PeriodicWorkRequestBuilder<SyncWorker>(15, TimeUnit.MINUTES)
    .setConstraints(Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresCharging(true)
        .build())
    .build()


2. 백그라운드 서비스를 피하세요.

오래걸리는 작업에 Service사용은 피하세요. 필요할때만 ForegroundService를 사용하세요

 

3. Jobscheduler

Jobscheduler 사용은 유저 응답을 요구 하지 않은 작업입니다.

 

4. 배터리 최적화

BatteryManager API 사용은 모니터와 배터리 상태 기반으로 작업을 최적화 합니다.

 

16. 안드로이드 앱 멀티 쓰레드에서 쓰레드 안전을 보장하는 방법

  • 시나리오

멀티 쓰레드에서 데이터를 처리해야합니다. 그리고 레이스 컨디션 상황을 피해야합니다.

  • 답변

1. 동기 블록

공유 자원을 동기화 하여 동시 수정을 방지하세요

synchronized(lock) { /* Critical section */ }


2. Atomic 함수

AtomicInteger 또는 다른 아토믹 클래스의 사용은 간단한 아토믹 작업에 사용됩니다.

val counter = AtomicInteger(0)
counter.incrementAndGet()

 

3. Dispatcher를 사용한 Coroutine 작업

백그라운드 작업에서 Disaptcher.IO를 사용하고, UI 업데이트 시 Dispatchers.Main을 사용하세요.

withContext(Dispatchers.IO) {
    // Background work
}



4. 쓰레드 안전 컬렉션

ConcurrentHasMap 또는 다른 쓰레드 안전 컬렉션은 공유 데이터 구조에 사용됩니다.

 

17. 앱에 실시간 데이터 동기화를 구현하는 방법

  • 시나리오

여러 디바이스 사이에 실시간 으로 데이터를 동기화해야합니다.

  • 답변

1. Firebase Realtime Database 사용

firebase listner 메커니즘은 실시간으로 데이터를 동기화해줍니다.

database.reference.child("data").addValueEventListener(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) { /* Update UI */ }
})


2. WebSockets

지연 시간이 낮은 통신을 위해 지속적인 웹소켓 연결을 설정하세요.

val client = OkHttpClient()
val request = Request.Builder().url("wss://example.com/socket").build()
val webSocket = client.newWebSocket(request, webSocketListener)



3. 충돌 해결 

동기화 중에 충돌을 해결하기 위해 타임스탬프 또는 버전 번호를 사용하세요

 

18. 앱 시작 시 최적화 방법

  • 시나리오

유저가 앱이 시작 시 알림이 느리다고 리포팅해왔습니다

  • 답변

1. 초기화 최대한 늦추기

즉시 필요로 하지 않다면 구성요소의 초기화를 연기하세요

 

2. 콜드 시작 최적화

어플리케이션 클래스의 onCreate 메서드에서 리소스 사용을 최소화하세요.

 

3. 스플래시 스크린 API
안드로이드 스플래시 스크린 API의 사용은 앱 실행을 매끄럽게 해줍니다. 

<style name="Theme.App.Starting" parent="Theme.Material3.DayNight">
    <item name="android:windowBackground">@drawable/splash</item>
</style>



19. 낮은 사양에 기기에서 앱 최적화 방법

  • 시나리오

한정된 자원을 가지고 있는 디바이스에서 효율적으로 앱을 실행시켜야 합니다.

  • 답변

1. APk 사이즈 줄이기

프로가드와 R8을 사용해서 코드 축소 및 리소스 최적화 

minifyEnabled true
shrinkResources true

 

 

2.  효율적인 리소스 사용

큰 이미지 파일 대신에 백터 드로어블 사용

 

3. 메모리 최적화

WeakReferences를 사용해서 메모리릭을 피하고, 사용되지 않은 리소스 정리

 

4. 동적 기능 전달

비 필수적인 기능은 Play Feature Delivery 를 사용하여 오프로드 하세요.

 

20. 모바일과 태블릿 디바이스에서 조정가능한 레이아웃 설계 방법

  • 시나리오

핸드폰과 태블릿에서 유연하게 이 작업을 이용하고, 큰 스크린에서도 효율적으로 사용해야합니다.

  • 답변

1. Fragments 사용 

Fragments는 플렉서블한 UI 플레이스먼트를 허용해줍니다.

  • 태블릿에서: twn-pane layout 사용
  • 폰에서: 싱글판 레이아웃 사용

 

2. 레이아웃 응답 

다른 레이아웃 파일을 스크린 사이즈에 맞게 사용하세요.

res/layout/activity_main.xml (for phones)
res/layout-sw600dp/activity_main.xml (for tablets)


3. ConstraintLayout

적응형 UI 생성은 ConstraintLayout을 사용합니다

 

4. WIndow Size Classes

컴포즈에 WindowSizeClass 을 사용하여 화면 크기에 따라 UI를 조정하세요.

 

5. 테스팅

다양한 스크린 화면을 테스트하세요. 안드로이드 에뮬레이터와 실제 디바이스에서요.

 

21. 컴포즈 앱에서 복잡한 상태 관리 방법

  • 시나리오

여러 데이터 소스와 중첩된 컴포넌트들이 UI로 복잡하게 되어있습니다.

  • 답변

1. 상태 올리기를 사용하세요.

상태를 공통 상위 컴포넌트로 올려, 여러 하위 컴포넌트에서 공유할 수 있도록 하세요. 

 

2. 상태 관리를 위해 StateFlow사용

StateFlow의 사용은 ViewModel에서 Ui로 상태를 노출할 수 있게 해줍니다. 

val uiState: StateFlow<UiState> = _uiState.asStateFlow()



3. 불편 상태 적용 

상태 객체는 변하지 않아야 하고, 업데이트를 필요로 한다면 copy 함수를 사용해야 하는게 보장되어야 합니다.

 

4. 단방향 데이터 흐름

단방향 데이터 흐름을 사용하여 상태 변화를 예측가능하게 관리하세요

  • 이벤트는 뷰모델에서 동작을 트리거 합니다
  • ViewModel은 동작을 처리하고 상태를 업데이트합니다.
  • UI는 상태 변화를 감지하고 이에 응답합니다.

 

5. 스냅샷 테스트

UI 상태 테스트는 컴포즈 테스트 유틸라이즈를 이용합니다

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

기타

transient 일시적인 

attempts 시도 횟수

prolonged 장기적인 

Obfuscation 난독화 

exponential 지수적인 ,기하급수적인 

draining 소모시키다

Establish 설립하다

shinking 축소하다 adaptive 적응형. 조정가능한various 다양한 nested 중첩된 ancestor 조상, 선조 unidirectional 단방향 predictably 예측간으한