마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

리사이클러뷰 + paging3 사용중인데 아이콘변경

0 추천
현재 구현하려는것이

리사이클러뷰를 쓰고있고, 뷰홀더에 있는 아이콘을 클릭시 api를 호출 후 정상적으로 호출하면 기존 아이콘을 다른 아이콘으로

바꿔주려고 합니다.

그래서 api 호출전 일단 뷰를 갱신하려고 response 클래스에 flag 변수를 하나 추가해줘서

바인드 뷰홀더의 init 에서 클릭리스너 달아두고 아이콘 클릭시 flag를 true로 변경해주고

바인드 뷰홀더에 onBind() 메소드 하나 둬서 거기에 flag를 true, false에 따라 기존아이콘인지 바뀐 아이콘인지

분기처리해줘서 처리해놨습니다

문제는 여기까지는 api 호출을 안쓰고 그냥 단순히 아이콘변경이니 됐는데 api를 호출해서 정상적으로 호출됐을경우

처리하려면 뷰홀더에서 클릭시 해당 어댑터를 사용하는 프래그먼트로 콜백으로 해당 클릭한 인덱스를 받아가지고

그 response클래스의 flag변수에 접근해서 하면 되지않을까? 생각했는데

paging3를 쓰다보니

viewmodel.apiCallMethod().collect {

 adapter.submitdata(it)

}

이렇게 던져주는데 문제는 저기 it이 response클래스가 아니고 로그찍어보면 paging321911290 이런식으로 나오잖아요..?

어떻게 해야될까요 이경우는
수원통학러 (3,570 포인트) 님이 2022년 4월 13일 질문

1개의 답변

0 추천

PagingData  API를 보시면 데이터를 변환하는 함수들이 존재합니다.

https://developer.android.com/reference/kotlin/androidx/paging/PagingData

map()을 사용해서 각 아이템의 상태를 바꾸시면 되지 않을까 생각되네요.

viewmodel.apiCallMethod()
.map { pagingData ->

     pagingData.map { item ->|
         item.copy(isCompleted = true)
     }
}

spark (225,780 포인트) 님이 2022년 4월 13일 답변
spark님이 2022년 4월 14일 수정
map을 추가해서 써보려는데 여기서도 it이 현재 pagingData<ResponseModel> 로 나오구요 copy자체가 안써집니다..
lifecyclescope.launch{
   viewmodle.apiCallMethod().map{item -> item.copy(isComplete=true) }.collect{}
}
아예 copy를 못써요..
답변에 있는 코드를 살짝 수정했어요.
찾았습니다 하려했는데 답글을 달아주셨네용
근데 이걸 collect랑은 같이 못쓰나요?
collect안에 item.map{ list.add(item) } 해서 써보려니 빈배열만 나오고
viewmodel.apicallmethod.map{ item -> item.map{ } ).collect {}
이렇게 써보려하니 collect에서 it이 pagingData<Unit>이네요
리스트를 갖고있긴 해야되는상황이라 저렇게 써야될거같기한데 방법이 있을까요?
뭐가 문제가 되는지 잘 모르겠네요. 기존에 pagingData.map이 없이 잘 사용하던 코드라면 위처럼 해도 문제없이 동작해야 할 텐데요.
viewmodel.apicallmethod.map{ item -> item.map{ list.add(listOf(item) } ).collect {}
이렇게 쓰고 디버깅 돌려보면 mpa 안에를 아예 안탑니다
정확히는 viewmodel.apiCallMethod.map{
   // 여기는 탐
   it.map {
     // 여기는 안탐
  }
}
이렇게됩니다
PagingData에 데이터가 없는 걸로 보이는데요.
지금 저상태로 해서 adapter.submitdata(it) 로 어댑터에 response 던져주고있는데
정상적으로 데이터는 나오고있습니다만 map 저기만 안타고 그냥 submitdata로 던져주고있어요 여기서 submitData(it)은 PagingData<responsemodel>이고 안타는 곳의 it은 responseModel입니다
코드를 거의 올리시지 않아서 어떻게 된 건지는 모르겠네요. 전 제가 올린 코드와 같이 해서 잘 사용 중이거든요. 님고 같이 아이콘을 변경하는 부분을 해당 코드에서 처리하고 있어요. responsemodel 와 PagingSource, Adapter 등 관련 부분을 확인해봐야 하실 것 같아요.
현재 map안타는 부분은 저거 그대로 빠짐없이 쓰고있구용
저 apiCallMethod를 타고 들어가면
suspend fun apiCallMethod() : Flow<PagingData<ResponseModel>> {
 return repo.getPaging3ApiData()
}
이렇게 쓰고있습니다
위의 코드만으로는 뭐라 말씀드릴 수 없구요, 페이징3는 이 외에도 뷰쪽에도 코드가 좀 필요하고, ViewModel, PagingSource도 구현되어야 하구요. collect하는 쪽에서는 Coroutine job관리도 해주어 하고, 최초에 PagingSource를 가져왔던 flow는 보관해서 사용해야 하는 등 추가작업 들이 있어요. 이런 부분을 올리신 코드를 기반으로는 뭐라 드릴 말씀이 없구요. 제일 좋은 건 디버깅을 해보시는 겁니다. PagingData에 어떤 데이터가 들어오는지 확인해 보세요. 디버거에서 PagingData의 api를 호출해서 확인해보실 수도 있구요.
pagingData.empty()가 아니라 pagingData.filter {true} 같이 확인해 보셔야 할 듯.
viewmodel.apiCallMethod.map{
   // 여기는 탐
   it.map {
     // 여기는 안탐
  }
}
여기서 it.map{ 여기에 브레이크 포인트걸어보면 null 이나오는데..
collect 해서 submitdata는 정상적으로 해서 리사이클러뷰에 잘뿌려주는데 어떤걸 확인해봐야되나요,.? response도 다잘내ㅕㄹ옵니다
님 말대로면, 제일 의심스러운 부분은 PagingSource의 구현입니다. PaingSource에서 데이터를 제대로 반환하고 있지 않은 걸로 보이네요.
그리고 ViewModel 에서는 flow를 매번 다시 생성하고 있는지 체크해 보세요. Flow는 멤버변수로 지정하시고 재사용을 하셔야 합니다.  아래처럼요, 그래야 동일한 Flow에서 stream을 계속 받을 수 있습니다.

private var searchFlow: Flow<PaginData<SearchItem>>?  = null

fun search(query: String): Flow<PaginData<SearchItem>> {
    var lastResult = searchFlow
    if (lastResult != null) return searchFlow
   
   return doSearch(query).also {
      searchFlow = it
   }
}

private fun doSearchQuery(query: String): Flow<PaginData<SearchItem>> {

}
pagingsource에서 response 클래스매핑은 제대로 들어오고
현재뷰모델에서는
suspend fun apiCallMethod() : Flow<PagingData<ResponseModel>> {
   return repo.getPagingData()
}
이렇게 바로 리턴을 해주고있습ㄴ디ㅏ
매번 새로운 Flow를 생성하고 있다면 문제가 됩니다. 한번 연결을 하고 지속적으로 collect를 하는 Flow이기 때문이죠. 기존에 데이터를 collect하고 있는 Flow가 있고 이 데이터들의 상태를 바꾸고 싶은거면 같은  Flow를 가지고 처리를 하셔야 겠죠. Flow를 왜 사용하고 계신지 잘 생각해 보세요. 페이징이 제대로 되고 있는지 테스트를 먼저 해보세요.  API 호출은 문제가 아니지만 Flow를 사용하는 방법이 문제인 것 같네요.
https://heeeju4lov.tistory.com/12
여기링크처럼 똑같은방식으로 페이징 이렇게 구현했구요 다른게 있다면 여기선 액티비티에서
lifecyclescope.launchWhenStarted를 쓰지만 저는 launch로 쓰는것만다르네용
님의 경우는 다른 상황처럼 보이는데요. 먼저 Flow에서 데이터를 collect하고 나서 이 Flow에서 collect했던 데이터의 상태를 바꾸는 거잖아요. 따라서 Flow를 다른 상태의 아이템을 두번  collect하도록 만들어 만들어야 하기 때문에 Flow를 재사용해야 할 듯 합니다. 같은 Flow를 가지고 최초 API 호출시 한번, 상태변경시 한번 더.
참조하신 소스코드를 받아서 간단한 데모코드를 만들었습니다.
https://github.com/krpot/PagingDemo
에서 확인하세요.
기존 코드에 이미지 위에 즐겨찾기 아이콘을 추가해서 클릭시 repository를 호출해서 flag를 변경하고 이 결과에 따라 화면을 업데이트 하도록 했습니다.
https://github.com/krpot/PagingDemo/tree/paging/app/src/main/java/com/remind/sampleapp/lorem_picsum 가 해당 코드가 들어있는 패키지입니다.
도움이 되시길 바래요.
예제까지 만들어주시니 감사합니다 참고하겠습니다!
...