티스토리 뷰
[Android] RecyclerView에서 Kotlin Android Extension, 제대로 알고 사용하자!
[Ellie] 2020. 3. 24. 17:51Kotlin에서 지원하는 기능 중에서 Kotlin 코드에서 XML 인스턴스로 바로 접근이 가능하도록 도와주는 Android Extension이라는 기능이 있다.
XML 인스턴스를 Kotlin으로 가져와서 사용할 수 있도록 만든 프로퍼티를 합성 프로퍼티(Synthetic Property)라고 한다.
이 프로퍼티는 클래스 내에 뷰 ID 이름으로 생성된다.
예를 들어 xml 코드에서 아래와 같은 Button을 하나 정의했다고 가정하자.
<Button
android:id="@+id/btn_save"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
이 Button은 Android Extension에 의해 Kotlin의 합성 프로퍼티가 만들어진다. 이 프로퍼티는 아래 예제 코드처럼 Button의 id인 ‘btn_save’를 통해 접근할 수 있다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_save.setOnClickListener {
// 버튼 클릭 동작 정의
}
}
이 합성 프로퍼티는 내부적으로 findViewById()를 호출한다. 그렇기 때문에 xml 인스턴스에 접근하기 위해 findViewById() 메서드를 직접 호출해서 인스턴스를 저장할 변수를 따로 만들지 않아도 되고, 결국 코드가 간결해지면서 생산성이 높아진다.
여기서 findViewById()는 호출 비용이 큰 메서드이라서 자주 호출하면 그만큼 성능에 지장이 생긴다. 그렇기 때문에 findViewById() 메서드 호출을 최소한으로 하는 것이 좋다. 이를 반영해 Kotlin은 어떤 합성 프로퍼티를 사용할 때, 최초의 한 번만 findViewById()를 호출한 뒤 클래스 내부에 캐시를 추가해서 그 다음 사용부터는 내부에 캐싱된 인스턴스를 반환한다.
이러한 Android Extension 기능을 이용해 RecyclerView의 ViewHolder를 사용할 때 유의할 점이 있다.
VIewHolder 내부에서 직접 합성 프로퍼티를 사용하는 것은 좋지 않다는 것이다.
예를 들어 아래의 코드를 보자.
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
with(holder.view.iv_image_item) {
setImageBitmap(imagebitmapImages[position]))
setOnClickListener {
// 이미지 클릭 동작 정의
}
}
}
위 코드는 iv_image_item을 id로 갖는 <ImageView> 합성 프로퍼티를 ViewHolder에서 직접 호출하고 있다.
액티비티 내에서 합성 프로퍼티를 사용할 때는 캐싱을 통해 findViewById() 메서드 호출을 최소화 하지만, 이처럼 RecyclerView의 ViewHolder 안에서 직접 합성 프로퍼티를 사용하게 되면 Binding 작업 시 캐시 객체를 저장할 공간이 없어 매번 findViewById() 메서드를 호출하게 되어 성능이 떨어진다.
이 문제를 해결하기 위해서는 아래 코드처럼 ViewHolder 내부에 각 뷰를 위한 프로퍼티를 추가하는 방법이 있다.
class ImageViewHolder(val view: View): RecyclerView.ViewHolder(view) {
val imageItem = view.iv_image_item
}
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
with(holder.imageItem) {
setImageBitmap(imagebitmapImages[position]))
setOnClickListener {
// 이미지 클릭 동작 정의
}
}
}
이렇게 하면 ViewHolder 내부에 뷰 인스턴스를 저장할 수 있는 필드가 생기면서 Binding 작업 시 findViewById() 메서드를 매번 호출하는 것이 아닌 ViewHolder에 추가한 프로퍼티를 가져와서 사용하는 구조로 바뀐다.
이 방법은 성능은 개선되지만 각 뷰의 인스턴스를 담는 프로퍼티를 직접 추가해야 하는 불편함이 있다.
그래서 나온 것이 LayoutContainer 인터페이스이다. 이 기능은 Kotlin 1.1.4 이상 버전부터 지원하고 있고, 아직 실험실 기능의 일부이기 때문에 LayoutContainer를 사용하기 위해서는 빌드 스크립트에 아래 코드를 추가해야 한다.
apply plugin: 'kotlin-android-extensions'
android {
...
}
dependencies {
...
}
androidExtensions {
// 실험실 기능 활성화
experimental = true
}
이제 LayoutContainer 인터페이스를 이용해 AndroidExtensionsViewHolder를 아래 코드처럼 정의하고, ImageViewHolder는 AndroidExtensionsViewHolder만 상속받도록 정의하면 된다.
abstract class AndroidExtensionsViewHolder(override val containerView: View)
: RecyclerView.ViewHolder(containerView), LayoutContainer
class ImageViewHolder(val view: View): AndroidExtensionsViewHolder(view)
위처럼 정의하면 자동으로 ImageViewHolder 내부에 사용하는 뷰 인스턴스 프로퍼티가 추가된다.
그렇기 때문에 아래 코드처럼 Binder에서 직접 합성 프로퍼티에 접근하는 것 처럼 작성해도 성능 문제가 발생하지 않는다.
[참고 사이트]
'Mobile > Android' 카테고리의 다른 글
[Android] Android Architecture (0) | 2020.03.24 |
---|---|
[Android] 컴파일 과정 (Dalvik vs ART) (0) | 2020.03.24 |
[Android] Dalvik과 ART의 GC 비교 (0) | 2020.03.24 |
[Android] JVM의 스택 기반 모델 vs DVM의 레지스터 기반 모델 (0) | 2020.03.24 |
[Android] RecyclerView로 리스트 보여주기 (0) | 2019.09.19 |
- Total
- Today
- Yesterday
- RuntimeException
- personal access token
- DiffUtil
- 내용제공자
- SOCKET
- gson
- GitHub
- SQLD
- SQLiteOpenHelper
- Android
- 부스트코스
- covariance
- 안드로이드
- MSSQL
- pecs
- kotlin
- SQL Server
- 알고리즘
- RecyclerView
- Python
- 파이썬
- SQL
- AsyncListDiffer
- Algorithm
- python3
- ViewHolder
- 프로그래머스
- Java
- AndroidStudio
- 위험권한
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |