안녕하세요. 오랜만에 글로 찾아뵙네요..ㅎㅎ
그동안 인턴십을 수행하면서 얻은 결과를 정리하느라 글을 못썼네요..ㅠㅠ
안드로이드 개발 인턴십을 통해 MVVM, AAC, RxJava, DI, Test에 대한 내용을 배웠고 앞으로 제가 정리한 내용을 공유하려 합니다.
먼저 제가 이전에도 다뤘던 MVVM과 Databinding에 대해 다시 한번 정리하는 시간을 갖도록 하겠습니다.
우선 제가 그동안 잘못 이해해온 부분부터 정리하도록 하겠습니다. 기본적으로 아래 두 게시물의 내용을 모두 이해하고 계신것으로 간주하고 시작해보겠습니다 !
위의 게시물들은 Data 또는 행동을 나타내는 ViewModel, 그리고 그 ViewModel을 View에 Binding하는 과정을 담고 있습니다. 이렇게 Databinding을 통해서 View와 ViewModel은 독립적인 구조를 가질 수 있게 되었습니다. 그로 인해 같은 로직과 데이터를 다루는 View가 여러개 존재한다면 View만 재구성하여 같은 ViewModel을 가질 수 있게 됩니다. 오늘 다룰 내용은 ViewModel의 Databinding에 대한 내용입니다. 저는 주로 Databinding을 Observable이라는 객체를 사용해서 하곤 했습니다. 하지만 AAC, RxJava와 같은 Reactive Programming을 제대로 활용하기 위해서는 LiveData라는 객체가 필수로 사용됩니다.
LiveData와 Observable간의 차이점은 아래 블로그에서 잘 설명하고 있습니다.
velog.io/@jojo_devstory/Android-LiveData...%EB%84%8C-%EB%88%84%EA%B5%AC%EB%83%90
LiveData는 '생명주기'라는 개념이 핵심적으로 사용됩니다. View의 생명주기를 ViewModel에 전달하고 해당 생명주기 안에서 Data의 변화상황을 지속적으로 '관찰'할 수 있게 됩니다. 물론 Databinding은 Observable과 동일하게 사용할 수 있습니다.
예제를 통해 LiveData를 사용해보도록 하겠습니다. Room으로부터 데이터를 가져오고 View에 Setting하는 간단한 예제입니다.
package com.msproject.myhome.mydays.main
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelProviders
import com.msproject.myhome.mydays.R
import com.msproject.myhome.mydays.application.MyApplication
import com.msproject.myhome.mydays.databinding.ActivityMainBinding
import com.msproject.myhome.mydays.main.event.EventActivity
import kotlinx.android.synthetic.main.activity_main.*
import javax.inject.Inject
class MainActivity :AppCompatActivity(){
lateinit var mainViewModel: MainViewModel
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
(application as MyApplication).appComponent.inject(this)
val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
mainViewModel = ViewModelProviders.of(this, viewModelFactory)[MainViewModel::class.java]
binding.model = mainViewModel
binding.lifecycleOwner = this
mainViewModel.initData(this)
}
}
<MainActivity.kt>
package com.msproject.myhome.mydays.main
import androidx.lifecycle.*
import androidx.lifecycle.Observer
import com.msproject.myhome.mydays.model.Event
import com.msproject.myhome.mydays.repository.CategoryRepository
import com.msproject.myhome.mydays.repository.EventRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*
import javax.inject.Inject
class MainViewModel @Inject constructor(private val eventRepository: EventRepository, private val categoryRepository: CategoryRepository):ViewModel(){
//usecase(getDailyEvents -> chart insert, getDailyMemo, insertMemo)
//field(eventPartitionView, events, eventStatisticView, eventCalendarDialog, eventSettingView)
val _eventList = MutableLiveData<List<Event>>()
val eventList:LiveData<List<Event>> get() = _eventList
fun initData(owner:LifecycleOwner){
eventRepository.getEventList().observe(owner, Observer {
eventList.postValue(it)
})
}
}
<MainViewModel.kt>
위의 View와 ViewModel을 살펴보면 @Inject, Factory와 같은 생소한 코드가 존재합니다. 이는 Dependency Injection을 위한 Dagger와 관련된 코드이니 오늘 다룰 내용과는 관계없습니다. 오늘은 Event, Category와 같은 데이터를 불러오는 Repository(Room으로부터 데이터를 가져오는)가 존재한다고 가정하면 되겠습니다. (DI와 관련해서는 다음 게시물로 찾아뵙겠습니다 ^^7)
오늘 다룰 내용의 핵심은 MainActivity의
binding.model = mainViewModel
binding.lifecycleOwner = this
mainViewModel.initData(this)
이부분과 MainViewModel의 데이터타입, initData함수입니다.
첫번째로 MainActivity에서 viewmodel을 정하고 Lifecycle을 지정해줍니다. 이를 통해 ViewModel은 View의 생명주기를 알게되고 위에서 말씀드렸듯이 해당 생명주기 동안 data를 observing할 수 있게 됩니다.
observing을 하기 위해 인터페이스인 LiveData의 구현체인 MutableLiveData를 사용하여 _eventList를 초기화하고, eventList는 _eventList를 주시하고 있습니다. 이를 통해 데이터의 변화를 두가지 변수를 통해 감지할 수 있도록 하고 동시에 캡슐화 또한 수행할 수 있습니다. 예를들어 _eventList는 private으로 접근지정을 할 수 있고, _eventList를 변경하면 해당 변경 사항을 eventList가 바로 감지할 수 있게됩니다.
예제에서는 repository에서 데이터를 바로 발행하지만 데이터가 애플리케이션 레벨에서 한번 더 변경 또는 가공될 수 있고, 이러한 과정을 하나의 LiveData로 수행한다면 데이터를 계속 지켜보는 비용에서 과부하가 일어날 수 있겠죠 ?? 때문에 두가지 변수를 통해서 데이터를 지켜보는 것입니다.
initData함수를 보시면 repository에서 가져온 LiveData를 observing하면서 viewModel의 _eventList를 발행하는 것을 볼 수 있습니다.(여기서 eventRepository의 getEventList는 LiveData<Event>형식의 메소드입니다.) LiveData의 데이터를 발행하는 방법은 postValue와 setValue가 있는데 postValue를 사용하는 이유는 데이터를 observing하는 것은 기본적으로 background thread에서 수행되기 때문에 직접적으로 값을 변경하는 setValue를 사용할 수 없기 때문입니다.
ViewModel을 이와같이 작성하고 databinding에 livedata객체를 사용하면 오늘 다룰 내용은 끝이 나게 됩니다.
그동안 Observable 사용하면 되지 왜 LiveData를 사용해야지?? 와같은 의문을 갖고 ViewModel을 작성하곤 했는데 LiveData를 사용하면 훨씬 더 데이터를 전략적으로 사용할 수 있다는 점을 깨닫게 되었습니다.
다음 시간에는 DI를 위한 Dagger에 대한 내용으로 찾아뵙도록 하겠습니다.
정리한 부분에 문제가 있거나 궁금하신점이 있으시다면 편하게 댓글 남겨주시면 감사하겠습니다 !!
'IT 프로그래밍-Android' 카테고리의 다른 글
BottomSheetDialog MVVM(ViewModel, Databinding) 적용방법 (0) | 2020.09.23 |
---|---|
[Android] Room 초기 데이터베이스 세팅 (1) | 2020.09.10 |
Retrofit + spring 사용 시 JsonObject 파싱 에러 (1) | 2020.06.18 |
[데이터바인딩] Room 데이터베이스 적용하기 (1) | 2020.05.14 |
[데이터바인딩] RecyclerView와 BindingAdapter (0) | 2020.04.29 |