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

DiffUtil에서 미리 값이 들어오는 것에 관해서.

0 추천

안녕하세요. 현재 꽤 오랫동안 고민을 해도 해결이 안되서 여기에 질문 올려봅니다.

현재 LiveData와 Listadapter 그리고 diffutil을 통해 recyclerview를 제작중입니다.

현재 제 서비스에서는 db에서 데이터를 그대로 가져올 수 없어서, 데이터를 재가공합니다. 

아래의 코드처럼 viewmodel에서 이런식으로 맞춰 data를 보내줍니다. 

fun getSchedules(selectedDate: String, category: String, secondCategory: String): LiveData<List<Schedules>> {
    val data = repository.getScheduleList(selectedDate, category, secondCategory)
    val result: LiveData<List<Schedules>> = Transformations.switchMap(data) { width ->
        dataFilter(selectedDate, width)
    }
    return result
}

그래서 데이터가 변경되면, adapter에있는 diffUtil로 데이터 변경되는걸 감지까지는 잘 하는데요.

complete라는 값을 줘서 했을때 1 안했을 때 0으로 값을 변경하는데, data class에 있는 나머지 데이터는 전부 변경값을 업데이트 해주면 areContentsTheSame에서 감지를 하는데 단 하나 complete만 계속 같다고 합니다...

data class Schedules(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "_id")
    var id: Int,
    @ColumnInfo(name = "ScheduleEmoji")
    var emoji: String,
    @ColumnInfo(name = "ScheduleContents")
    var contents: String,
    @ColumnInfo(name = "ScheduleCategory")
    var category: String,
    @ColumnInfo(name = "ScheduleComplete")
    var complete: Int,

 

override fun areContentsTheSame(oldItem: Schedules, newItem: Schedules): Boolean {
    val complete = oldItem.complete == newItem.complete
    Log.d("contents_complete :", complete.toString())

    Log.d("contents_old_complete :",oldItem.complete.toString())
    Log.d("contents_new_complete :",newItem.complete.toString())

    Log.d("contents_complete_id :", oldItem.id.toString())우

위의 로그를 찍었을때 계속 newItem, oldItem가 complete만같게 나옵니다.. 하지만 db를 확인했을 경우 제대로 값은 업데이트 됩니다. (app inspection에서 확인했습니다.)

이렇게 DiffUtil에서 특정 값이 변경된 후의 값으로 감지하는 경우 어떻게 해야하나요..?

sososososoddddd (120 포인트) 님이 2022년 12월 14일 질문

1개의 답변

0 추천

DiffUtil.Callback의 areItemsSame, areContentsSame함수 두개다 oldItem ==newItem으로 비교해 보시고
ListAdapter를 사용하실 때는 arraylist같은 mutablelist 를 대신 list 같은 readonly그리고val 타입을 사용하시는게 안전합니다. ArrayList같은 타입을 사용하면 리스트 안의 내용이 변경이 되도 같은 오브젝트라서 diffutil이 같은 데이터로 인식합니다. 그리고list를 사용하시더라도 내용이 바뀌면 기존 리스트의 내용을 변경하는 대신 (예를 들면 var 타입 멤버 변경) 새로운 리스트를 리턴하는 게 좋습니다. 코틀린의 경우는 collection api들이 list 같은 readonly를 사용할 경우 복사본을 리턴하게 하기 때문에 list타입을 사용하시면 될 겁니다.

Schedules 엔터티를 ui에 그대로 사용하지 마시고
val타입 멤버를 가진 클래스를 하나 만드셔서 변환시킨 다음 List타입을 사용하세요. 이렇게 해야 강제적으로 리스트에 변경이 생길 때 무조건 복사본을 리턴하는 구조가 때문에 부작용을 없앨 수 있습니다.

data class SchduleUiEntity (
    val id: Int,
    val emoji: String,
    val contents: String,
    val category: String,
    val isCompleted: Boolean
)


fun Schdules.toUiEntity(): ScheduleUiEntity {
     return SchduleUiEntity(
         id = this.id,
         emoji = this.emoji,
         contents = this.contents,
         category = this.category
         isCompleted = this.complete == 1
     )
}

fun getSchedules(selectedDate: String, category: String, secondCategory: String): LiveData<List<ScheduleUiEntity>> {
    val data = repository.getScheduleList(selectedDate, category, secondCategory)
    return Transformations.switchMap(data) { width ->
        dataFilter(selectedDate, width).map { dbEntity: Schedules ->
              dbEntity.toUiEntity()
        }
    }
}

 

그리고 complete를 변경하시면 getSchedules를 다시 호출하시기 바랍니다.

spark (227,830 포인트) 님이 2022년 12월 14일 답변
spark님이 2022년 12월 14일 수정
...