본문 바로가기
Android Q&A/Android One a day

[안드로이드 면접] - 16 :

by 후추부 2023. 2. 17.

1. ListView 의 ViewHolder 패턴에 대해 설명하고 왜 사용하는 지 설명하시오.

더보기

ViewHolder 이란? View 를 관리를 하는 Holder를 가지고 화면에서 보이는 아이템 개수만 생성하고, 스크롤이 발생하면 ViewHolder에 등록한 뷰를 재사용한 후, 데이터만 바꿔주기 패턴이다. 이는 앱의 효율성이 향상되는 패턴이다.

 

ListView 는 일반적으로 내부 화면에 보여질 뷰 배열만 몇 개 생성하고, 스크롤 되었을 때 이것을 재사용하게 된다.

이 부분은 ConvertView 를 이용하여 메모리 낭비를 줄인다고 생각하면 된다.

 

하지만, 뷰를 인플레이팅하는 과정은 ConvertView 를 이용하여 줄였지만, 뷰의 id 를 찾아서 데이터 세팅하는 과정은 계속해서 진행하기 때문에 고비용 우려가 생긴다. (뷰의 id 를 찾는 과정이 자원이 더 든다는 말이다.)

 

아이템마다 findViewById() 메서드를 사용하여 뷰의 id 값을 찾아 아이템 세팅하는 과정을 ViewHolder 패턴으로 해결할 수가 있다. 

 

어떻게 해결할까?

view 의 tag를 이용한다고 생각하면 된다.

💡 여기서 잠깐? 그러면 tag 는 무엇인가? 옷에 붙어있는 옷 태그를 생각하면 된다. 그와 비슷하다. (어떤 표시를 하기 위해 붙인) 꼬리표, 번호표 라는 의미이다.

다시 설명을 이어하자면, 지속적으로 생성되는 데이터를 뷰와 함께 Tag 를 이용하여 저장시킨다. (getView() - setTag)

반대로 데이터를 연결시켜주고자 하는 곳에 getTag 를 통해 꺼내어 사용한다.

 

이런 식으로 각 리스트 아이템의 뷰에 대한 처리 시, 아이템을 추가할 때 사용한 데이터가 필요로 할 때 setTag 를 이용하여 데이터를 링크 시키고, 데이터가 필요한 순간에 getTag 를 이용하여 링크된 데이터를 가져와 사용한다.

 

따라서, findViewById() 를 사용하여 ViewGroup 밑에 있는 모든 뷰들을 전부 한 번씩 순회하며 id 값을 비교하는 과정이 없어짐으로 자원이 더 적게들 것이다.

 

2. ANR 이 발생하는 이유와 어떤식을 방지할 수 있는지 설명하시오.

더보기

발생 이유

1. 5초 이내에 입력 이벤트에 대한 응답이 없을 경우 (UI Thread)

2. 브로드캐스트 리시버의 onRecieve() 가 10초 내에 리턴되지 않을 경우 (I/O Thread)

 

예방하는 방법

  • 시간 소모가 많은 작업은 메인(UI) 스레드에서 실행하기 보단, 다른 스레드(I/O Thread)를 통해 처리하기 
    • 서브 에서 시간이 오래걸리는 작업을 수행하고, Handler 를 이용하여 작업상태 메시지를 메인 스레드에 전달한다.
    • AyncTask 를 이용하여 핸들러 사용없이 작업과 작업에 대한 내용을 실시간으로 UI 업데이트 한다.
    • RxJava 의 스케줄러를 이용하여 서브스레드에서 작업한다.
    • Kotlin의 Coroutine 을 이용하여 별도 코루틴을 생성하여 작업한다.
  • 사용자에게 프로그레스바 등을 이용해 작업의 진행 과정을 안내해 기다리도록 한다.

 

3. Android Serializable, Parcelable  에 대해서 설명하시오.

더보기

안드로이드 개발을 하다보면 액티비티 간 데이터를 공유해야 할 경우가 종종 생기는데 그 때 사용한다.

모든 데이터를 공유할 때 Serializable, Parcelable 이 필요한 건 아니다.

String 이나 Int 같은 Primitive Type 는 데이터 전달할 수 있지만, 객체 즉 우리가 비즈니스 로직에 필요하여 만든 객체는 Serializable(직렬화) 또는 parcelable 한 객체로 만들어야만 해당 객체를 보낼 수가 있다.

 

Serializable(직렬화)란?

객체를 저장 장치에 저장 또는 네트워크 전송을 위해 텍스트나 이진형식으로 변환하는 것이다. 

반대로, 역직렬화는 텍스트나 이진형식으로 저장된 데이터로부터 원래의 객체를 만들어내는 것이다. 

 

Serializable 은 표준 JAVA 인터페이스이다.

따라서, 상속을 받아서 간단하게 구현할 수 있고, 내부 구현이 되어있으니 우리 개발자가 모르게 알아서 구현되어 돌아간다는 말이다. 하지만 이 말은 편한만큼 성능 측면에서 좋지 않을 수 있다. 실제로도 그렇다.

 

내부적으로 Serializable 은 reflection 을 사용하기 때문에 프로세스 동작 중에 많은 객체들이 추가로 생성되고 사용되고, 사용이 끝난 후에 가비지 컬렉터가 또 지우기 위해 동작이 된다. 이 부분이 앱 성능을 낮게 만들 수 있다. 실제로도 그렇다는 데이터 분석이 나오긴 했다.

 

Parcelable(포장가능한)이란?

Parcelable 은 안드로이드 SDK 가 포함되고 있는 인터페이스이다. 

위에서 설명한대로 동작은 같지만, Serializable 이 시스템 내부적으로 구현된 reflection 을 Parcelable은 사용하지 않도록 설계되어 있기 때문에 우리 개발자들이 수동적으로 작업 해줘야 할 부분이 존재한다.

 

정리하자면, Serializable 은 시스템비용을 발생시키고, Parcelable는 구현 및 유지보수 비용이 든다.

 

하지만, 코틀린을 사용할 경우 @Parcelize 어노테이션으로 인해 굉장히 사용이 편해진다.