Observer
객체에 알리면서 UI와 데이터 상태를 동기화시킵니다.Lifecycle
객체에 결합되어 있으며 연결된 수명 주기가 끝나면 자동으로 삭제됩니다.LiveData
객체가 시스템 서비스에 한 번 연결되면 리소스가 필요한 모든 관찰자가 LiveData
객체를 볼 수 있습니다. 앱 수준의 build.gradle
에서 다음 종속 항목을 추가합니다.
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
특정 유형의 데이터를 보유할 LiveData
의 인스턴스를 생성합니다. 일반적으로 ViewModel
클래스 내에서 이루어집니다.
ViewModel
클래스 내에서 이루어지는 이유는 LiveData 인스턴스를 특정 액티비티나 프래그먼트 인스턴스에서 분리하고 구성 변경(화면 회전 등)에도 LiveData 객체가 유지되도록 하기 위함입니다.
class MainViewModel: ViewModel() {
var result: MotableLiveData<String> = MutableLiveData()
// LiveData 갱신
fun setName(value: String) {
result.value = value
}
fun getName(): MutableLivaData<String> = result // LivaData 반환
}
대부분의 경우 앱 구성요소의 onCreate()
메서드가 LiveData
객체 관찰을 시작하기 적합한 장소이며 이유는 다음과 같습니다.
다음 코드는 LiveData
객체 관찰을 시작하는 방법을 보여줍니다.
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 코드 생략..
// onChanged() 메서드를 정의하는 Observer 객체를 만듭니다. 이 메서드는 LiveData객체가 보유한 데이터 변경시 발생하는 작업을 제어합니다.
val resultObserver = Observer<String> {
result -> binding.tvResult.text = result.toString()
}
// observe()를 사용하여 LiveData객체에 LifecycleOwner를 사용하여 Observer 객체를 연결합니다.
// observe()를 호출하면 onChanged() 콜백 함수가 즉시 호출되어 getName()에 저장된 최신 값을 제공한다.
viewModel.getName().observe(this, resultObserver)
binding.button.setOnClickListener {
if (binding.etName.text.toString().isNotEmpty()) {
// LiveData 객체 업데이트
viewModel.setName(binding.etName.text.toString())
} else {
binding.tvResult.text = "No value"
}
}
}
}
관찰자의 수명 주기가 STARTED 또는 RESUMED 상태이면 LiveData는 관찰자를 활성상태로 간주합니다.
class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
private val stockManager = StockManager(symbol)
private val listener = { price: BigDecimal ->
value = price
}
// onActive(): LivaData 객체에 활성 상태의 관찰자가 있을 때 호출됩니다.
override fun onActive() {
stockManager.requestPriceUpdates(listener)
}
// onInactive(): LiveData 객체에 활성 상태의 관찰자가 없을 때 호출됩니다.
override fun onInactive() {
stockManager.removeUpdates(listener)
}
// setValue(T)메서드도 있는데, 이는 LiveData 인스턴스의 값을 업데이트하고 모든 활성 상태의 관찰자에게 변경사항을 알립니다.
}
그리고 다음과 같이 프래그먼트에서 클래스를 사용할 수 있습니다.
class MyFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
// Update the UI.
})
}
관찰자에게 LiveData
객체를 전달하기 전에 객체에 저장된 값을 변경하고 싶거나 다른 객체에 값에 따라 다른 LiveData
인스턴스를 반환해야 하는 경우가 있습니다. Lifecycle
패키지는 이러한 시나리오를 지원하는 도우미 메서드가 포함된 Transformations
클래스를 제공합니다.
val userLiveData: LiveData<User> = UserLiveData()
// userLiveData에 있는 값의 일부를 String 타입의 userName LiveData로 변환하여 저장할 수 있습니다.
val userName: LiveData<String> = Transformations.map(userLiveData) {
user -> "${user.name} ${user.lastName}"
}
Transformations.switchMap()
map()과 마찬가지로 LiveData객체에 저장된 값에 함수를 적용하고 결과를 래핑 해제하여 다운스트림으로 전달합니다. switchMap()에 전달된 함수는 다음 예와 같이LiveData
객체를 반환해야 합니다.
private fun getUser(id: String): LiveData<User> {
...
}
val userId: LiveData<String> = ...
// userId LiveData에 저장되어있는 값에 getUser(id) 함수를 적용시켜 LiveData<User> 객체를 반환합니다.
val user = Transformations.switchMap(userId) { id -> getUser(id) }