티스토리 뷰

ETC

안드로이드 면접 질문

비용러브 2022. 2. 10. 15:45

1. 안드로이드 애플리케이션 클래스는 무엇인가요?

> 안드로이드의 Application Class 는 액티비티 및 서비스와 같은 다른 모든 구성 요소(액티비티(Activity), 서비스(Service), 방송수신자(Broadcast receiver), 콘텐츠 제공자(Content provider), 인텐트(Intent))에 접근 가능한 기본 클래스입니다. 또한 애플리케이션 프로세스가 생성될 때, 가장 먼저 초기화 됩니다. 그렇기 때문에, 보통 앱 전역에서 일관성있게, 사용하는 요소들을 등록하여 사용하곤 합니다.

 

2. 컨텍스트란 무엇인가요?

Context

> Context 는 리소스에 접근하거나, 데이터베이스나 프리퍼런스에 접근하는 등 기타 등등 역할들을 제공한다. 앞으로 비교할 다른  Context 와 다른 중요한 점은 애플리케이션에서 현재 실행되고 있는 환경을 가지고 있다는 것이다.

 

Application Context

> 애플리케이션 라이프 사이클에 종속되어 있다.(애플리케이션이 만들어지고 유지되다가, 종료될 때 없어진다) 애플리케이션 컨텍스트는 라이프사이클이 현재 컨텍스트와 상관없는 다른 컨텍스트가 필요하거나 액티비티 활동 범위를 벗어난 컨텍스트를 필요할 때 사용할 수 있습니다.

Ex) Dialog 는 액티비티 Context 가 필요하고, Toast 는 Application Context 로 사용할 수 있다. (Toast 는 액티비티와 별개로 Window 를 가지고 있다)

 

Activity Context

> 액티비티 안에서 사용할 수 있는 Context 로 액티비티 라이프 사이클에 종속되어 있다. 액티비티의 라이프사이클과 맞물리는 작업에서 필요할 때 사용한다. 제일 많이 사용하는 화면이동에서 A 에서 B 로 이동할 경우, 이때  A 의 액티비티 컨텍스트가 필요하다. 물론 Application Context 로도 화면을 실행시킬 수 있지만, 이때는 인텐트에 Intent.FLAG_ACTIVITY_NEW_TASK 플래그가 필요하다

 

3. ARM64-v8a(64), ARMv7, ARMx86 등.. ABI(Application binary interface)가 무엇인가요?

> 안드로이드 디바이스는 다양한 CPU 를 사용하여 만들고, CPU에서 제공하는 명령셋은 다양하다, 대표적인것이 ARMv7 이 있고, 우리가 작성한 코드가 javac에 의해 바이트 코드(.class)로 바뀌고, Dalvik VM(현재는 ART VM) 안에서 JIT 컴파일을 통해 기계어로 번역 되는데, 이때 이 기계어를 해석하고 명령하는데, 이때 CPU 마다 명령을 실행하는 방법이 다르고, 실행 가능한 바이너리 형식, 명령 집합 등이 정의되어 있는 것이 애플리케이션 바이너리 인터페이스(ABI) 이다.

 

4. 바이트 코드를 안드로이드에서 바로 실행할 수 있나요 ?

> 바로 실행할 수 없다. Java 바이트 코드를 실행하려면 JVM (Java Virtual Machine)이 필요하지만,  안드로이드는 JVM 대신 Dalvik VM 을 사용하여,  메모리, 배터리 수명 및 성능에 더 초점을 맞춰 개발이 되었기 때문에 실행할수 없다.(라이센스 문제도 있었다고 한다.) 또한  dx 라는 안드로이드 도구를 사용하여 Java 클래스 파일을 Dalvik 실행 파일(.dex 파일)로 바꿔 실행한다.

Dalvik VM : 32비트만 지원 (JIT 컴파일러 - 실행하면 만들어 놓고)

ART VM : 32비트, 64 비트 모두 지원 (AOT 컴파일러 - 미리 만들어 놓고)

 

5. 빌드타입이 무엇인가요?

> 빌드타입이란 현재 사용하고 있는 라이브러리, 모듈 등의 빌드 방법을 정의하는 것이다. 안드로이드 앱이 패키징 되고, 빌드 될 때 그래들을 사용하여 빌드 타입을 정의할 수있다. 빌드할 때 추가되어야하는 리소스를 분리하여 적용할 수 있다. 또한 build variant 와 다양하게 조합해서 제품의 flavours 나 build type 을 정의할 수 있다.

Ex) flavor = [local, dev, stage, real]

Ex) buildType = [debug, release]

localDebug, localRelease, devDebug, devRelease, stageDebug, stageRelease, realDebugm realRelease 등.

 

6. 안드로이드 빌드 프로세스에 대해 간략하게 설명해보세요.

> 첫째로 Android asset packaging tool (AAPT) 를 사용하여 리소스(/res 이하 파일들)를 컴파일한다. 이때 R.java 라고 불리는 하나의 클래스로 컴파일 되어진다.

두번째로 .java 파일들이 javac 로 부터 .class 파일로 컴파일 된다. 그리고 클래스 파일들은 dx 툴(Android SDK tools 아래 포함되어 있다)에 의해 달빅 바이트 코드(classes.dex)로 변환된다.

마지막으로 APKbuilder 에 의해 apk(android packagin key) file이 만들어 진다. 현재는 각 디바이스의 해상도, 언어, abi 타입등으로 나눠 들어가 있는 apks 로 제공되어 나중에 디바이스에 필요한 리소스만 가지고, 애플리케이션을 만드는 AAB(android app bundle) 로 사용되기도 한다

 

7. 액티비티가 무엇인지 한줄로 정의해보세요

액티비티는 기본적으로 컨테이너의 역할을 하고, 사용자 인터페이스 화면을 구성하는 컴포넌트이다.

 

8. 액티비티 라이프 사이클에 대해 말해주세요.

onCreate() : 뷰가 처음 만들어 질 때 호출된다. 보통 뷰를 만들고, 초기화 하거나 번들로부터 데이터를 받아오는 코드를 많이 작성한다.

onStart() : 액티비티가 유저에게 가시적일 때 호출된다. 더 나아가 액티비티가 포그라운드로 오면, onResume 이 호출되고, 내려가면 onStop 이 호출된다.

onRestart() : onStop() 이 호출되었던 액티비티가 포 그라운드로 돌아오면 호출되는 메서드 이후 onStart() 를 호출한다.

onResume() : 액티비티가 유저와 상호작용하고 있을 때 호출된다. 액티비티 스택에서 가장 위에 있는 액티비티는 유저의 입력을 받을 수 있다.

onPause() : 액티비티가 백그라운드로 가기전 상황으로 부분적으로 가려질 때 호출된다. 아직 Killed 되지 않은 상황이다.

onStop() : 액티비티가 보여지지 않게 되었을 때 (백그라운드로 갔을 때) 호출된다. 더 나아가 액티비티가 종료되면 OnDestroy 가 호출되고, 포 그라운드로 돌아오면 onRestart() 가 호출된다.

onDestroy() 액티비티가 종료될 때 호출된다.

 

9. onCreate() 와 onStart 는 어떤 점이 다른가요 ?

> onCreate() 메소드는 애플리케이션이 시작되거나, 액티비티가 삭제된후 재생성될 때, 액티비티 사이클에서 한번만 호출된다. (앱의 구성요소 (언어, Orientation, 등) 가 변경되어 액티비티가 부서지고 다시 생성될 때 등)

> onStart() 메소드는 언제든지 액티비티가 유저에게 보여줄 준비가 되었을 때(가시적일때) 호출될 수 있다. 전형적으로 onCreate() 이후나, onRestart() 이후에 호출된다.

 

10. 액티비티에서 onPause 나 onStop 이 호출되지 않고 onDestroy 가 호출되는 경우는 언제인가요 ?

onCreate() 함수 안에서, finish() 를 호출할 경우 시스템은 직접 onDestroy() 를 호출한다.

 

11. LMK 가 무엇인가요 ?

LMK(Low Memory Killer) 안드로이드에서 가용 메모리(available memory)가 부족할 때 프로세스들을 죽이는 동작이다.

 

LMK의 목적

LMK의 목적은 바로 가용 메모리를 확보하는 것이다. 이것이 부족하면, PC나 휴대폰 등과 같은 시스템들의 성능이 크게 떨어집니다. 무지무지 느려지는 거죠. 심하면 앱 하나 띄우는데 몇 초 이상의 시간이 걸릴 수도 있습니다. 이런 문제를 방지하기 위해서 안드로이드는 사용하지 않는 프로세스들을 메모리에서 지워야 합니다. 여러분들이 가지고 계시는 안드로이드 폰들에서 LMK가 바로 이러한 역할을 수행하고 있습니다.

 

LMK 의 Priority

LMK 는 우선순위를 가지며 우선순위가 낮은 경우 부터 메모리에서 해제된다. (아래로 갈수록 우선순위가 낮다)

foreground process(현재 포그라운드에 올라온 애플리케이션, 현재 동작하고 있는 서비스)

visible process(사용자가 화면에서 볼 수 있지만 포그라운드가 아닌 경우 ex. 다이얼로그 에 가려진 onPause 상황 )

service process (직접 화면에 보이지는 않지만, 백그라운드에서 동작하는 데이터 업로드 또는 다운로드 경우, 오랫동안 동작한 서비스)

cached process (현재 사용하지는 않지만, 메모리에 적재되어 있는 프로그램)

 

OOM Killer와 LMK

안드로이드는 먼저 LMK 로 진행하다가, 더 이상 내릴 프로그램이 없을 때 OOM 순서를 밟는다.

 

 

1. 왜 액티비티 클래스 의 onCreate() 메소드 안에서 setContentView() 를 사용해야 할까요?

> 액티비티의 onCretate() 메소드는 액티비티 불릴 때 한번만 호출이 되기 때문에, 초기화에 자주 사용된다. onResume() 또는 onStart() 같이 여러번 호출 될 수 있는 곳에서 호출하는 것은 매우 비효율적인 코드이다.

 

2. 액티비티 클래스의 onSavedInstanceState(), onRestoreInstanceState() 메소드의 역할은 무엇인가?

> onSaveInstanceState() - 액티비티가 pause 되기 전에 데이터를 저장하는데 사용합니다.

onRestoreInstanceState() - 액티비티가 파괴되고, 다시 재생성될 때, 액티비티가 가지고 있는 번들로부터 데이터를 회복할수 있다. 또한 onCreate() 와 onRestoreInstanceState() 콜백 메서드는 같은 번들 객체를 전달 받는다. 그래서 보통은 데이터를 회복하는 코드를 onRestoreInstanceState() 에 많이 작성하는 편이며, onCreate 에서 savedInstance를 받아 처리하는 경우에는 처음 실행이 되는지, 재생성되는 것인지 판단하기 위해서, 데이터의 null check 가 필요하다. null 이라면 처음 생성되는 것이고, 아니라면 재생성이다.

 

3. 안드로이드 런치모드들에 대해서 설명해주세요.

> 런치모드란 액티비티가 어떤 방식으로 실행되야하는지에 대한 방식들이다.

Standard : 시스템이 액티비티가 시작된 작업(Task)에서 액티비티의 새 인스턴스를 만들고 인텐트의 경로를 이것으로 지정한다. 액티비티는 여러 번 인스턴스화될 수 있고, 각 인스턴스는 서로 다른 작업에 속할 수 있으며 한 작업에 여러 개의 인스턴스가 있을 수 있다.

Eg : 현재 A -> B -> C 로 쌓여있는 액티비티 스택이 있다고 가정해보자, 현재 B를 다시 실행하고 싶은 상태이고, 이를 standard 로 액티비티 B를 실행할 경우 A -> B -> C -> B 이 된다.

 

SingleTop : 액티비티의 인스턴스가 이미 현재 작업의 맨 위에 존재하는 경우, 시스템은 새 액티비티 인스턴스를 만드는 대신 onNewIntent() 메서드를 호출하여 인텐트를 해당 인스턴스로 라우팅한다. 액티비티는 여러 번 인스턴스화될 수 있고, 각 인스턴스는 서로 다른 작업에 속할 수 있으며 한 작업에 여러 개의 인스턴스가 있을 수 있다(다만 백 스택의 맨 위에 있는 액티비티가 액티비티의 기존 인스턴스가 아닌 경우에만 이것이 적용된다).

SingleTop 런치모드와 비슷하지만, 실행하는 액티비티가 액티비티 스택의 Top 일 때 새로운 인스턴트를 만드는 것이 아니라. 현재 인스턴스스의 onNewIntent()를 호출한다 

Eg : 현재 A -> B 로 이루어진 액티비티 스택이 있다고 가정해보자. 만약 C 액티비티를 SingleTop 으로 실행하면 A -> B -> C로 정상적으로 쌓일 것이다. 그리고 현재 A -> B -> C 로 이루어진 액티비티 스택에서 C를 SingleTop 으로 다시 실행하면 A -> B -> C -> C가 되는 것이 아니고 여전히 A -> B -> C 이다.

 

SingleTask : 시스템이 새 작업을 만들고 새 작업의 루트에 있는 액티비티를 인스턴스화한다. 하지만, 액티비티의 인스턴스가 이미 별개의 작업에 존재하는 경우, 시스템은 인텐트의 경로를 기존 인스턴스로 지정한다. 이때 새 인스턴스를 만들지 않고, 해당 인스턴스의 onNewIntent() 메서드를 호출하는 방법을 사용한다. 한 번에 액티비티 인스턴스 한 개씩만 존재할 수 있습니다.

Eg : A -> B -> C -> D 로 이루어진 액티비티 스택이 있다고 가정하자. 현재 액티비티 D를 SingleTask 모드로 실행하면, A -> B -> C -> D이고 D의 onNewIntent() 가 불리운다. 그리고 액티비티 B를 SingleTask 로 실행하면, 액티비티 스택은 A -> B 로 바뀌고, 액티비티 C, D 는 파괴된다

 

SingleInstance : "singleTask"와 동일하다. 단, 인스턴스가 있는 작업에 대해 시스템이 어떤 액티비티도 시작하지 않은 경우는 예외이다. 액티비티는 언제나 자신의 작업의 유일무이한 멤버이고, 이것으로 시작한 액티비티는 모두 별개의 작업에서 열린다.

Eg : A -> B -> C -> D로 이루어진 액티비티 스택이 있다. 만약 액티비티 D를 singleInstance 모드로 실행할 경우, 아래와 같이 작업이 분리된다

Task 1 - A -> B -> C

Task 2 - D

 

4. 화면 회전을 했을 때 액티비티가 어떻게 동작하나요 ?

> 화면 회전을 했을 때, 현재 만들어진 액티비티 인스턴스는 파괴되고 새로운 Orientation 을 가진 액티비티 인스턴트가 만들어진다. 그렇기 때문에 데이터를 백업해두지 않으면, 메모리에서 해제되기 때문에 이를 유의하여 개발해야한다.

 

5. 화면 회전이 되었을 때, 데이터가 초기화 되는 것을 어떻게 막을 수 있나요 ?

> 기본적인 문제 해결 접근으로는 ViewModel, onSavedInstanceState() 두 방법을 사용하는 방식이 있다.

그렇다면 이들을 어떤식으로 사용해야할까요 ?

ViewModel : 뷰모델은 라이프 사이클에 Aware 하다고 한다. 알고 있다 or 알고 있기 때문에 좀더 유연해진다 정도로 받아드리면 될 것 같다. 그리고 뷰모델은 앱의 Configuration (rotatin 등) 이 바뀌어 액티비티가 파괴되어도, 파괴되지 않고, 액티비티가 재생성되었을 때 다시 연결된다. 만약에 화면 회전을 3번하면 액티비티 인스턴스는 부서지고 만들어져 3번 다 다른 인스턴스이지만, 뷰모델 인스턴스는 하나이다.

그렇기 때문에 뷰모델 클래스에 데이터를 저장하면 자연스럽게 해결할 수 있다. 또는 onSaveInstanceState() 메소드를 사용하는 방법이다.

 

6. 인텐트를 사용하여 새로운 액티비티를 실행할 때, 액티비티 스택을 클리어할 수 있는 두가지 방법을 설명해보세요.

> 첫번째 접근으로는 FLAG_ACTIVITY_CLEAR_TOP 플래그를 사용하는 방법이다.

두번째 접근으로는 FLAG_ACTIVITY_CLEAR_TASK 와 FLAG_ACTIVITY_NEW_TASK 플래그를 를 동시에 사용하는 방법이다.

 

7. FLAG_ACTIVITY_CLEAR_TASK 와 FLAG_ACTIVITY_CLEAR_TOP 의 차이점은 무엇인가요 ?

> FLAG_ACTIVITY_CLEAR_TASK 는 호출된 클래스의 존재하는 모든 인스턴스들을 포함한 작업(Task)에 있는 모든 액티비티들을 클리어 시킬 때 사용한다. (액티비티 스택에 쌓인 모든 액티비티를 클리어 시키고, 한개의 액티비티를 실행할 때 자주 사용하게 된다)

FLAG_ACTIVITY_CLEAR_TOP 는 액티비티가 실행될 때 (set), 액티비티 스택에 이미 존재한다면, 그 아래 있는 모든 작업(Task)이 제거 되고, 현재 실행하는 작업(TASK) 이 작업 리스트(Task list)의 루트가 된다. 반면에 액티비티 스택에 존재하지 않는다면, 작업 리스트(Task list) 의 루트에 새로운 인스턴스가 생성된다. 보통 FLAG_ACTIVITY_NEW_TASK 와 함께 사용하는 것이 추천된다.

 

8. 컨텐츠 프로바이더(Content providers)에 대해서 설명해주세요 

> 컨텐츠 프로바이더는 하나의 어플리케이션에서 요청시에 다른 어플리케이션으로 데이터를 제공한다. 어플리케이션의 데이터 보안으로 인해 구조화된 데이터 구조를 가지고 있도록 정의되어 있다. 컨텐츠 프로바이더는 기본적으로 다른 프로세스에서 다른 프로세스로 데이터를 제공할 수있는 인터페이스를 가지고 있다. 만약 컨텐츠 프로바이더를 이용하여 데이터 접근을 원한다면, Application Context 안에 있는 ContentResolver 오브젝트를 사용하여 클라이언트(요청하는 쪽)로서 커뮤니케이션한다 (요청 받는 쪽이 서버라고 보면 되겠다

 

9, 컨텐츠 프로바이더를 사용하여 데이터에 접근하는 방식을 간략하게 말해보세요.

> 먼저 Access permissions 를 획득했는데 확인해야한다. 그리고 컨텍스트 객체 안에 있는 ContentResolver 객체를 가져온다.

ContentResolver 의 query() 함수를 통해 데이터를 끌어온다(Retrieving). query() 함수는 Cursor 를 리턴하기 때문에, 커서를 사용하여 각각의 칼럼을 가져와서 데이터를 사용한다.

 

 

1. 서비스에 대해서 설명해주세요 

> 서비스는 보통 백그라운드에서 오랜시간 동안 수행될 때 적합한 어플리케이션 컴포넌트 이다. 그리고 유저 인터페이스를 제공하지 않는다. 심지어 유저가 해당 어플리케이션과 상호작용하고 있지 않을 때도 말이다. 서비스는 3가지 타입이 있다.

Foreground Service : 포그라운드 서비스는 유저에게 알림을 줄 수 있는 명령을 수행한다 예를 들어 우리는 음악을 실행하기 위해서 포그라운드 서비스를 사용할 수 있고 사용자에게 알림을 표시해주어야 한다.

Background Service : 백그라운드 서비스는 유저에게 직접적으로 알림을 주지 않는 서비스를 수행한다. 안드로이드 API 26 레벨 이상에서는 백그라운드 서비스를 사용하는 것이 금지 되었다. 그래서 이런 작업들에는 WorkManager 를 사용해야 한다.

Bound service : 바운드 서비스는 bindService() 메소드를 호출함으로써, 어플리케이션 컴포넌트에 바인딩 되는 서비스이다. 바운드 서비스는 요청을 보내거나, 결과를 받는 클라이언트-서버 인터페이스가 제공된다. 또한 다른 어플리케이션 컴포넌트에 바운드 되어 있는 경우에만 실행된다.

참고 > https://developer.android.com/guide/components/services?hl=ko

 

2. 서비스와 인텐트 서비스의 다른점은 무엇인가요 ?

> 서비스는 안드로이드 서비스를 위한 기초(Base) 클래스이다. 그래서 어떤한 서비스로도 확장되거나, 만들어질 수 있다. 서비스를 직접적으로 상속받은 클래스는 기본적으로 메인 스레드에서 실행되기 때문에 UI를 Block 할 수 있다. 그래서 비교적 간단한 태스크를 수행하거나, 무거운 작업을 하게 될 경우에는 다른 스레드를 만들어 사용해야한다.

인텐트 서비스는 서비스의 하위 클래스 이다. "인텐트" 라고 불리는 비동기 요청을 처리하는 서비스이다. 클라이언트는 startService() 메소드를 통해 요청을 보낸다. 인텐트 서비스는 필요에 따라 실행되며, 워커 스레드를 사용하여 각각의 인텐트가 처리된다. 작업을 모두 수행하면, 종료한다.

 

3. Thread 와 AsyncTask 의 다른점은 무엇인가?

> 스레드가 수행되기 위해서는, 메인 스레드에서 분리하여 실행된다. 그러나 스레드를 취소하는 것은 우아하게(elegantly) 되지 않는 경우가 많고, 안드로이드 설정이 변경되는 것을 처리할 수 없다. 또한 스레드에서는 UI를 변경할 수 없다. 자바의 메소드이다.

AsyncTask 는 5ms 보다도 짧은 작업을 처리 할 수 있다. 또한 스레드와는 다르게 UI를 업데이트 할 수 있는 부분이 있다. 하지만 무겁고 다양한 작업들을 수행한다면 퍼포먼스는 저하된다. 안드로이드 라이브러리에 있는 메소드이다.

 

4. 핸들러란 무엇인가?

> 핸들러는 스레드를 관리하기 위한 객체이다. 핸들러는 메세지를 받거나 처리하는 방법을 정의할 수 있다. 그들을 액티비티 라이프사이클 외에서 사용할 때에는 사용한 뒤 적절히 해제(Cleaned up) 시켜줘야 한다. 그렇지 않으면 메모리 누수(thread leaks)가 발생할 것 이다.

핸들러는 메인스레드와 백그라운드 스레드 혹은 백그라운드 스레드 사이의 커뮤니케이션을 가능하게 한다.

핸들러는 몇초나 몇분 단위로 정기적으로 해야하는 백그라운드 작업을 수행하는데 선호된다.

 

5. Job Scheduling 이란 무엇인가요?

> 안드로이드 L 에서 추가된 Job scheduling api 는 이름에서 느껴지는 그대로, 메모리 최적화, 배터리 소모량, 연결성 조건(connectivity condition)에 대한 작업을 할 수 있게한다. 또한 작업들의 일괄적으로 작업할 수 있는 배치 기능을 제공한다. 안드로이드 시스템은 작업들을 결합하여, 배터리 소모를 줄 일 수 있다. (가령 와이파이가 연결 되었을 때만 파일 업로드/다운로드 등)

몇가지 예시를 들자면,

  • 디바이스의 배터리에 전원이 공급중 일 때
  • 네트워크 연결이나 와이파이의 연결이 필수 일 때
  • 중요하지 않거나, 사용자 직접적으로 개입하는 작업이 아닌 경우
  • 중요하지 않지만, 주기적인 배치 작업을 실행하는 경우

6. Activity와 AsyncTask 의 라이프 사이클이 어떤 관계이 있나요? 어떤 문제가 결과적으로 발생할 수 있나요 ? 그리고 어떻게 문제를 회피할 수 있을 까요 ?

 

7. onTrimMemory 메소드는 무엇인가요?

 

8. Android Bound Service란 무엇인가요?

 

9. AIDL 과 Messenger Queue 를 비교하여 말해보세요.

 

10. ThreadPool 이란 무엇인가요 ? 몇개의 분리된 스레드에서 사용할 때 효율적으로 하는 방법은 무엇일까요 ?

 

11. Serializable 과 Parcelable 에 대해 비교하며 설명해주세요.

 

 

 

'ETC' 카테고리의 다른 글

CS 기술면접 면접 질문  (0) 2022.02.10
DB, Framework, Deploy 면접 질문  (0) 2022.02.10
Front End Interview Handbook  (0) 2022.02.10
Tech Interview FOR BEGINNER  (0) 2022.02.10
FRONTEND - 웹브라우저 & HTML 면접 질문  (0) 2022.02.10
댓글