liveData는 라이프 사이클을 아는 데이터라고 했고, observe가 가능한 클래스임. 그래서 실시간으로 데이터 변화를 감지 할 수 있다.

 

 hilt를 사용하여 obsereve가 자동으로 제거된다고 했으므로 좀 더 편하게 사용 할 수 있음

(이건 내가 확신이 없어서 다음에 디버그 포인트 찍어서 진짜 그런지 확인해 봐야겠음.. 좀 큰 프로젝트를 만들어서라도..

근데 lifecycleOwner를 사용해서 관찰자에 대응되는 객체의 상태를 보고 Destroyed가 되었을때 관찰자를 삭제 한다고 하므로 누수 걱정이 없다는게 장점이니 확실한 거 같음.)

 

 

1.TransFormations

라이브데이터의 저장된 값을 변경하고싶을때 사용한다.

라이브데이터에 적용하여 onChange가 되었을때 작동하여 변화를 감지한다.

라이브 데이터 객체가 관찰되고 있을때만 작동한다

  1) map 

  2)switchMap

  3)distinctUntilChanged

나는 이런식으로 사용했음.

 

Viewmodel 

val userId = MutableLiveData<Int>()

fun setUserId(id: Int) {
    userId.value = id
}
val user = Transformations.switchMap(userId){ repository.getUser(it).asLiveData() }

UI Controller

viewmode.user.observe(..) {
	...
}

fun changeUser(id:Int){
	viewmodel.setUserId(id)
}

changeUser(..)

이렇게 뷰모델에서 userId를 바꿀수 있게 만든다. 이게 버튼을 클릭한 방식이던가 textInput을 사용한 방식이던가에 상관없이 id가 새로 갱신되고 이 새로 갱신된 id를 UserId로 삽입하고 이것을 user이 변화를 감지하여 repository에서 그 유저의 데이터를 라이브데이터로 반환하여 이 라이브데이터를 observe해서 사용하도록함.

 

2. MediatorLiveData 

 이게 좀 제일 중요하다고 본다 라이브데이터를 사용함에 있어서 다양하게 사용하기 위해서 여러 종류의 라이브 데이터를 관찰하고 이것을 하나의 라이브 데이터로 반환하거나 다른 데이터로 반환하는 함수를 만들기 위해서는 이것을 사용!

addSource함수를 사용하여 라이브데이터를 소스데이터로 등록하고 이 소스데이터의 변화를 감지하여 사용함

매우 다양하게 사용 할 수있다고 생각함.

 

 

이렇게 사용하는게 맞는지는 모르겠지만 일단 하나의 예시로 내가 사용했던 방식을 예시로 들어보겠음.

나는 페이지네이션을 페이징데이터를 사용하지 않고 사용해보고 싶었다. 그래서 버튼을 클릭하거나 어떠한 listner을 통해서 room데이터에 있는 데이터를 몇개 더 가지고 오려고함. 그리고 여기에 type을 정하여 그 타입에 맞는 데이터를 가지고 오도록 할 것임.

 

 

1)Dao

@Query("SELECT * FROM data WHER type =:type ORDER BY id DESC LIMIT :count")
    fun getData(count:Int,type:Int): Flow<List<Data>>

2)Repository

fun getPageData(count:Int,type:Int) = Dao.getData(count,type)

3)Viewmodel

val countInput = MutableLiveData<Int>()
fun setCount(count: Int) {
    countInput.value = count
}

val typeInput = MutableLiveData<Int>()
fun setType(type: Int) {
    typeInput.value = type
}

val result = object: MediatorLiveData<List<Data>>(){
	var count =Transformations.switchMap(countInput){ MutableLiveData<Int>(it) }
    var type = Transformations.switchMap(typeInput){ mutableLiveData<Int>(it)}
    var query : Pair<Int,Int>? = null 
    init{
    	addSource(count){count ->
        	type.value?.let{ type -> 
            	query = count to type
            	value = repository.getData(query.first,query.second).asLiveData().value
            }
        }
    	addSource(type){type->
        	count.value?.let{ 
            	count -> query = count to type
            	value = repository.getData(query.first,query.second).asLiveData().value
    		}
        }
    }
}

위와 같은 식으로 쓰고 사용하는 uicontroller에서 setCount와 setType을 이용해서 필요한 생성자들의 값을 지정해 준다.

위에서 사용한  a.value?.let의 경우에는 receiver가 null이 아닐때만 작동을 하기때문에 둘 중에 무엇을 먼저 업데이트하는가는 문제가 되지 않는다. 

 

viewmodel.setType()
viewmodel.setCount()
viewmodel.reslut.observe(..){
	...
}

 위의 함수를 적절한 위치에다가적용만 하면 우리가 원하는 값을 얻을 수 있을것임. 

 

 

 

리워크