LiveData란?
Android Jetpack의 구성요소로 수명주기를 인식하는 관찰 가능한 데이터 홀더 클래스입니다.
- 수명주기 인식 -> Activity, Fragment, Service 등 다른 앱의 수명주기를 고려
- 관찰 가능한 -> Observer패턴
- 데이터 홀더 클래스 -> 많은 양의 Operation, stream을 쓰기에는 부적절
바꿔 말하면 Observer클래스로 표현되는 관찰자의 수명주기가 Started, Resumed이면 LiveData는 관찰자를 활성 상태로 간주하고 해당 관찰자에게만 정보를 업데이트합니다.
LiveData 장점
1. UI와 데이터 상태의 일치 보장
Observer패턴이므로 LiveData의 데이터가 변경될 때 Observer객체에게 알려 UI를 업데이트할 수 있습니다. Observer객체가 대신 UI를 업데이트 하므로 개발자가 업데이트 할 필요가 없습니다.
2. 메모리 누수 없음
Observer객체는 Lifecycle객체에 결합되어 있으므로 Lifecycle가 끝날 시 자동으로 삭제됩니다.
3. 중지된 활동으로 인한 비정상 종료 없음
액티비티가 백 스택에 있을 때 Observer객체의 수명주기가 비활성 상태에 있으면 어떤 LiveData이벤트도 받지 않습니다.
4. 수명주기를 더 이상 수동으로 처리하지 않는다
LiveData는 수명주기의 상태 변화를 인식하여 업데이트와 중지 등 모든 것을 자동으로 관리합니다.
5. 최신 데이터 유지
다시 활성화될 때 업데이트받으므로 항상 최신 데이터를 유지할 수 있습니다.
6. 적절한 구성 변경
기기 회전과 같은 구성 변경으로 인해 프래그먼트가 재 생성되면 사용 가능한 데이터를 즉시 받습니다.
7. 리소스 공유
앱에서 시스템 서비스를 공유할 수 있도록 싱글톤 패턴을 사용하는 LiveData객체를 확장하여 시스템 서비스를 래핑 할 수 있습니다. 서비스에 한 번 연결되면 리소스가 필요한 모든 관찰자가 Livedata객체를 볼 수 있습니다.
LiveData객체
LiveData객체를 사용하기 위해 3가지 단계가 있습니다.
- LiveData인스턴스 생성 (일반적으로 ViewModel클래스의 프로퍼티로 생성합니다)
- onChanged()를 정의하는 Observer객체 생성 (onChanged() 메서드는 LiveData객체가 보유한 데이터 변경 시 발생하는 작업을 제어합니다. 일반적으로 액티비티나 프래그먼트 같은 UI 컨트롤러에 만듭니다)
- observe() 메서드를 이용하여 LiveData객체에 Observer객체를 연결 (observer() 메서드는 LifecycleOwner객체와 Observer() 객체를 패러미터로 받습니다. Observer객체가 LiveData객체를 구독하여 변경사항에 관한 알림을 받습니다)
LiveData객체에 저장된 값을 업데이트하면 연결된 LifeCycleOwner가 활성 상태(STARTED, RESUMED)에 있는 관찰자가 트리거 됩니다. 이를 이용하면 개발자가 별도의 UI업데이트할 필요없이 자동으로 업데이트 할 수 있습니다.
LiveData객체 만들기
LiveData는 List와 같은 Collections부터 모든 데이터와 함께 사용할 수 있는 래퍼 클래스입니다. 일반적으로 ViewModel 클래스의 프로퍼티로 사용되며 getter메서드를 통해 액세스 됩니다.
class TestViewModel : ViewModel() {
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
}
처음 LiveData객체의 데이터가 설정되지 않습니다.
LiveData관찰
대부분의 경우 onCreate() 콜백 메서드가 LiveData 객체 관찰을 시작하기 적합한 시점입니다.
onCreate() 메서드에서 관찰을 시작하면 액티비티나 프래그먼트의 onResume() 메서드에서 중복 호출을 방지할 수 있습니다. 또한 활성 상태가 되는 즉시 데이터를 업데이트하기 위함입니다. 앱 구성요소는 STARTED 상태가 되는 즉시 관찰하고 있던 LiveData객체에서 최신 값을 업데이트받습니다.
일반적으로 LiveData는 데이터가 변경될 때 활성 상태인 관찰자에게 업데이트합니다. 예외로, 관찰자가 비활성 -> 활성 일 경우 업데이트 합니다. 만약 비활성 1 -> 활성1 -> 비활성 2 -> 활성2 일 경우 활성 1 이후 값이 변경됐을 때 업데이트를 받습니다.
class MainActivity : AppCompatActivity(){
private lateinit var binding: ActivityMainBinding
//should implementation 'androidx.activity:activity-ktx:1.4.0'
private val model: TestViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
var count = 0
//anonymous
val observe = object: Observer<String>{
override fun onChanged(newName: String) {
binding.textButton.text = newName
}
}
//should import androidx.lifecycle.Observer
//Lambda
model.currentName.observe(this, Observer { newName ->
binding.textButton.text = newName
})
binding.textButton.setOnClickListener {
count++
model.currentName.value = count.toString()
}
}
}
Observer객체를 매개변수로 전달하여 observer()을 호출하면 onChanged()가 즉시 호출되어 model.currentName에 저장된 최신 값을 가져옵니다. LiveData객체가 mCurrentName에 값을 설정하지 않았다면 onChanged()는 호출되지 않습니다.
일반적으로 람다식으로 사용하지만 onChanged()가 어떻게 호출되는지 보기 위해 익명 객체로 자바처럼 호출했습니다.
Button.text에 직접적으로 값을 넘겨주지 않았음에도 바뀌는 모습을 볼 수 있습니다.
LiveData객체 업데이트
LiveData는 setValue(T), postValue(T) 메서드로 저장된 값을 수정할 수 있습니다. 일반적으로 MutableLiveData는 ViewModel에서 사용되며 ViewModel은 변경이 불가능한 LiveData객체만 관찰자에게 노출합니다.
class TestViewModel : ViewModel() {
private val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
fun setCurrentName(input: String){
currentName.value = input
}
fun getCurrentName(): LiveData<String>{
return currentName
}
}
class MainActivity : AppCompatActivity(){
private lateinit var binding: ActivityMainBinding
private val model: TestViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
var count = 0
model.getCurrentName().observe(this, Observer { newName ->
binding.textButton.text = newName
})
binding.textButton.setOnClickListener {
count++
model.setCurrentName(count.toString())
}
}
}
setCurrentName(T)을 호출하면 증가하는 count값과 함께 Observer객체의 onChanged() 콜백이 호출됩니다. 위 코드에선 버튼 이벤트만 보여주지만, setValue(), postValue()는 네트워크 요청 또는 DB 로드 완료에 응답하는 등의 다양한 이유로 업데이트하기 위해 호출할 수 있습니다.
LiveData를 쓰지 말아야 하는 경우
Android Dev Summit 18 영상을 보면 LiveData를 쓰지 말아야 하는 3가지 경우를 알려줍니다.
• 대량의 연산자나 스트림을 써야 하는 경우 경우 RX를 쓰는 게 더 낫습니다.
대량의 변환 과정을 추가하려고 애쓸 필요 없습니다. LiveData는 단순히 데이터 홀더로서 디자인됐습니다.
• UI나 라이프 사이클과 관련이 없는 연산(백엔드 서비스)을 할 경우 콜백 인터페이스를 쓰는 것이 더 낫습니다.
LiveData가 수명주기를 인식하는 데이터 홀더로 디자인됐기 때문에 용도 자체가 다릅니다.
• one-shot operation chaning를 쓸 예정이라면, 코 루틴을 쓰거나 Rx자바를 쓰는 게 더 낫습니다.
마찬가지로 디자인된 목적이 아닙니다.
참고
LiveData 개요 | Android 개발자 | Android Developers
LiveData를 사용하여 수명 주기를 인식하는 방식으로 데이터를 처리합니다.
developer.android.com
Fun with LiveData (Android Dev Summit '18)
Android Jetpack: LiveData
'안드로이드 > 기본개념' 카테고리의 다른 글
플로우 차트(Flow Chart) (0) | 2023.03.23 |
---|---|
DP? SP? DPI? PX? (0) | 2022.06.14 |
Inflate (0) | 2022.06.13 |
Activity란? (0) | 2022.06.13 |
Context? (0) | 2022.06.06 |