개발중인 앱에서 RecyclerView는 Epoxy를 사용하고 있는데 상당히 편리함을 누렸지만 제대로 알지못하고 있는거 같아서 공식문서를 쭉 훑어보았다. 이번 글에서는 공식 문서와 소개 페이지에서 설명하고 있는 요소들 중에서 놓치기 쉬웠던 부분들 몇가지를 체크하려한다.
EpoxyAttribute
EpoxyAttribute를 사용하면 자동 Diffing에 사용되는 hashCode()
나 equals()
같은 메소드가 생성되는데, 이를 원하지 않는다면 @EpoxyAttribute(hash=false)
로 꺼둘 수 있다.
클릭 리스너처럼 매번 bind 될때마다 재생성되는 필드들에 적용하면 좋다.
Hiding Models
View가 조건부로 보여지고 숨겨져야할때 사용할 수 있다. model.show(boolean)
으로 조건에 따라 보이고 숨겨지게 할 수 있으며 hide()
나 show()
각각의 메소드도 존재한다.
숨겨진 모델은 기술적으로 RecyclerView에는 존재하지만, 어떠한 공간도 차지하지 않는 빈 레이아웃으로 교체된다. 이는 즉슨 모델의 Visiblity를 바꾸려면 notifyItemChanged
가 필요하다는 말이된다. 하지만 이는 EpoxyController 안에서는 허용되지 않고, 같은 기능을 원한다면 addIf(boolean)
을 사용하라.
Model IDs
모델이 초기화될때 유니크한 ID를 할당받는데, id(long)
으로 명시할 수도 있다. 서버나 DB로 부터 받은 정보는 명시적으로 ID를 주는게 일반적이다. 어댑터는 자동 Diffing이나 ViewState 저장등을 Stable ID에 의존한다. 이러한 기능을 사용하려면 Stable ID를 활성화 해둬야한다(기본적으로는 true).
혹시나 서버에서 오는 고유값이 겹치게되면 오류가 발생할 수 있는데, setFilterDuplicates(true)
를하게되면 동일한 ID 값을 가진 모델이 있다면 첫번째 모델은 어댑터에 남겨두고 두번째 모델은 제거된다. 이때, onExceptionSwallowed
가 트리거될 것이다.
모델의 ID를 명시적으로 정해줄때는 아래 세 가지 방법이있는데, 각각의 이상적인 용도는 주석을 확인하라.
model.id(long) // 가장 일반적
model.id(string, long) // 다른 모델과 long형 ID가 겹칠거같을때, namespace 지정
model.id(string) // 숫자로 ID를 정의할 수 없는 경우
Auto Model
헤더나 로딩처럼 항상 어댑터에 존재하는 모델의 경우 @AutoModel
어노테이션으로 선언해두면 Epoxy는 해당 모델에 유니크한 ID를 할당하여 생성해둔다. 이는 다른 어댑터 인스턴스를 통틀어 Stable하며, 화면 회전시 View State를 저장하는데 사용될 수 있다.
public class PhotoController extends EpoxyController {
@AutoModel HeaderModel_ header;
@AutoModel LoadingModel_ loader;
...
@Override
protected void buildModels() {
header
.title("My Photos")
.addTo(this);
for (Photo photo : photos) {
new PhotoModel_()
.id(photo.getId())
.url(photo.getUrl())
.comment(photo.getComment())
.addTo(this);
}
loader
.addIf(loadingMore, this);
}
}
Asynchronous Support
EpoxyController는 두개의 Handler 인스턴스를 생성자에서 받고 있는데, 하나는 모델 빌딩에, 하나는 Diffing에 사용된다. 기본적으로는 메인 스레드를 사용하며, 성능 향상을 위해 비동기 처리를 허용하도록 바꾸어줄 수 있다.
- Note: EpoxyController가 가장 처음에 모델을 빌드할때는 Async Handler를 지정했다고한들 “항상” 메인 스레드에서 실행된다. 이는 View들이 처음 생성되었을때 동기적으로 saved state를 복원하도록하기 위함이다.
쉽게 사용하려면 그냥 AsyncEpoxyController
를 상속받아 사용하면 된다.
기본세팅 자체를 바꾸는 방법도 있는데, 아래와 같은 식으로 전역적으로 적용해줄수도 있다.
HandlerThread handlerThread = new HandlerThread("epoxy");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
EpoxyController.defaultDiffingHandler = handler;
EpoxyController.defaultModelBuildingHandler = handler;
또한 비동기 Handler를 생성해주는 유틸 함수 EpoxyAsyncUtil#getAsyncBackgroundHandler
도 있으니 필요하면 사용하도록한다.
출처
'프로그래밍 > Android' 카테고리의 다른 글
[Android] IllegalStateException: Method addObserver must be called on the main thread (0) | 2022.07.17 |
---|---|
Bitrise에서 버전명(혹은 버전코드) 환경변수로 사용하기 (0) | 2022.07.13 |
Upstream Flow, Downstream Flow (0) | 2022.05.20 |
LiveData를 버리고 StateFlow를 써야할까요? (0) | 2022.05.05 |
안드로이드 Unity 플러그인 만들기 (0) | 2022.04.16 |