ListAdapter와 RecyclerView의 UI Update 방식의 차이

 

촬영 버튼을 통해 사진을 촬영하고, RecyclerView를 통해 촬영된 사진을 관리하는 어댑터를 필요로 했다.

 

처음에는 촬영버튼을 눌렀을 때, 사진을 저장하고 RecyclerView를 통해 저장된 사진의 path를 건넨 뒤, 어댑터를 통해 삭제요청이 들어오면 path의 이미지를 지우는 방식으로 구현하였다.

이렇게 되면 데이터 변경에 대한 notify()를 직접 수행해주면서 UI 업데이트를 해 줘야 한다는 애로사항이 있었다.

 

반면, ListAdapter와 DiffiCallback을 구현하게 되면 리스트를 Viewmodel차원에서 관리하며 옵저버 패턴을 통해 submitList로 리스트를 넘겨주면 자동으로 UI 업데이트가 가능하다.

 

외에도 추가적으로고 path를 통해 저장하는 기존 방식은 불필요하게 빈번한 저장/삭제가 일어난다는 문제가 있었기에,

 Bitmap을 통해 이미지를 관리하다가 최종 선택 시, 한번에 bitmap을 저장하는 방식으로 구현하고자 했다.

 

 

ViewModel에서 관리될 BitmapList

private val _capturedImages: MutableLiveData<ArrayList<Bitmap>> = MutableLiveData(arrayListOf())

    val capturedImages : LiveData<ArrayList<Bitmap>>
        get() = _capturedImages

 

본 프래그먼트

        cameraViewModel.capturedImages.observe(viewLifecycleOwner) { itemList ->
            picturesAdapter.submitList(itemList)
        }

 

근데 해당 방식을 수행하는데 데이터 변경에 대한 실행 (submitList) 코드는 실행이 되는데 UI에 반영이 안되는 것이다.

 

        cameraViewModel.capturedImages.observe(viewLifecycleOwner) { itemList ->
            picturesAdapter.submitList(itemList)
            binding.adapter = picturesAdapter
        }

 

어댑터를 다시 설정해 주어야만 데이터가 표시 되는 것을 확인할 수 있었다.

 

좀 찾다보니 해당 글을 확인할 수 있었는데 

디버깅 방식이 유사하여 웃음이 나왔다.

 

  Log.wtf("WTF", movieList.size.toString())

 

 

android - ListAdapter submitList not updating - Stack Overflow

 

ListAdapter submitList not updating

I have this issue with the pagination infinite scroll in RecyclerView, I am adding all new item using .addAll() movieList.addAll(it.movieList) adapter.submitList(movieList) Log.wtf("WTF&quo...

stackoverflow.com

 

 

정리하자면 다음과 같다.

 

ListAdapter의 경우에는 old list와 new list의 내용을 DiffiCallback을 통해 비교하는 방식으로 작동하기 때문에,

mutable list를 사용할 경우 이전 목록에 해당하는 (old list) 리스트가 없기 때문에 차이를 감지할 수 없다는 것.

 

해결책은 다음과 같다.

        cameraViewModel.capturedImages.observe(viewLifecycleOwner) { itemList ->
            picturesAdapter.submitList(itemList.toList())
        }

결국 핵심은 바뀌는 리스트를 넘겨주는 것이 나타내고 싶은 상태가 고정된 리스트 (toList로 새 리스트에 복사)로 전달하는 것이 핵심이다.

 

submitList(itemList.toList())

 

 


추가적으로 LiveData를 다루는 데 있어

단순 _capturedImages.value!!.add(image)와 같이 MutableLiveData의 value인 ArrayList에 add/remove를 통해 수정/삭제하여 옵저버 패턴이 반응하기를 기대했었는데 value 자체가 바뀐 것이 아니라 반응하지 않는 것을 확인했다.

 

그래서 다음과 같이 setValue(value)를 재설정하는 것으로 수정하였다.

val currentList = _capturedImages.value ?: arrayListOf()
bitmap?.let { currentList.add(0, it) }
_capturedImages.value = currentList

+ Recent posts