2019. 2. 14. 09:51ㆍProgramming/Android
기존에 릴리즈된 Android App을 유지보수하면서, RecyclerView에 아이템을 추가하는 코드가 때때로 IndexOutOfBoundsException
로 인해 App Crash가 발생하는 경우가 발생했다. Android 자체를 너무 오랜만에 보다보니, RecyclerView에 대한 것부터 알아봐야했다. 자세한 내용을 정리하기엔 시간이 부족한데다가, 잘 정리된 글들이 많아서 이하의 링크로 대체한다.
RecyclerView, Android Developers
Android RecyclerView 사용하기, Taehwan 님
RecyclerView에 대한 고찰, Dudmy 님
스크롤이 발생했을 때 스크롤의 위치가 마지막일 경우 다음 검색결과를 불러온 뒤, notifyItemRangeChanged(int positionStart, int itemCount)
를 호출하여 특정 부분을 갱신하고 있었다. 데이터가 많아지는 경우 렌더링을 최대한 효율적으로 처리하고 싶었던 것 같은데, 사용방법이 조금 이상했다. 검색조건이 변경되는 경우 검색결과가 초기화되는데, 이 때 positionStart
의 값으로 0을, itemCount
의 값으로 검색 결과의 갯수(20개로 제한되어 있었다)를 전달하고 있었다.
이 경우에 왜 IOOBE
가 발생하는지는 좀 더 리서치가 필요하다. 하지만 리서치를 하지 않더라도 이전에 검색결과에 대한 ArrayList가 초기화되는 반면에, 이전에 렌더링됐던 데이터들을 전혀 고려하지 않았다는 사실은 이상했다. (예를들어서 기존에 40개의 검색결과를 ArrayList
로 가지고 있을 때, 새로 20개의 검색결과를 받아와서 ArrayList
의 내용을 대체하고 notifyItemRangeChanged(0, 20)
을 호출한다. 이 때 이미 RecyclerView에 렌더링됐던 20~40에 해당하는 아이템들은 어떻게 처리되는가?)
처음에는 위의 내용을 파악하지 못해서, notifyDataSetChanged()
를 호출하는 것으로 IOOBE
가 발생하는 것을 회피할 수 있었다. 하지만 역시 검색결과가 많아지는 경우 성능에 대한 사항이 우려됐기에, 검색결과를 새로 받아와서 ArrayList
를 초기화하는 경우에만 notifyDataSetChanged()
를 호출하는 것으로 수정했다. (검색결과를 초기화하지 않고 다음 검색결과를 불러와서 ArrayList
에 추가하는 경우, notifyItemRangeChanged
를 호출해도 문제가 발생하지 않는다.)
RecyclerView의 최적화를 위하여 지원하는 메소드를 확인하고자 할 경우, 아래의 링크를 참조하도록 하자. RecyclerView에 대한 내용과 마찬가지로, 잘 정리된 글이 많아 링크로 대체한다.
RecyclerView, Android Developers
RecyclerView Adapter Refresh, GsBOB 님
public void notifyItemRangeChanged(int positionStart, int itemCount) {
notifyItemRangeChanged(positionStart, itemCount, null);
}
public void notifyItemRangeChanged(int positionStart, int itemCount,
@Nullable Object payload) {
// since onItemRangeChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload);
}
}
위는 notifyItemRangeChanged의 내용이다. 일단 자세한 내용은 주말에 다시 리서칭해서 작성해야 할 듯 하다.
'Programming > Android' 카테고리의 다른 글
Android Installation error: INSTALL_FAILED_UPDATE_INCOMPATIBLE (0) | 2019.02.18 |
---|---|
Oreo 이상의 OS에서 Notification이 발생하지 않는 문제 (0) | 2019.02.14 |
WebView와 WebSettings (0) | 2019.02.12 |
loop에서 findViewById 사용하기 (getIdentifier) (0) | 2019.02.11 |
Android Gradle Plugin 3.0의 Implementation과 api (0) | 2019.02.07 |