코드랩 Room 사용하기3
SleepTrackerFragment화면에서 STOP버튼을 누르면 SleepQualityFragment로 넘어가서 Quality를 설정해줘야한다.
SleepTrackerViewModel
private val _navigateToSleepQuality = MutableLiveData<SleepNight>()
val navigateToSleepQuality: LiveData<SleepNight>
get() = _navigateToSleepQuality
그리고 STOP버튼을 누르면 중단했을때의 oldNight 객체를 넣어준다.
fun onStop(){
viewModelScope.launch {
val oldNight = _tonight.value?:return@launch
oldNight.endTimeMilli = System.currentTimeMillis()
update(oldNight)
_navigateToSleepQuality.value = oldNight
}
}
fun doneNavigating() {
_navigateToSleepQuality.value = null
}
이 코드는 프래그먼트 이동 후 null로 초기화해주는 코드이다.
SleepTrackerFragment에서는navigateToSleepQuality를 관찰하고 있다가. 값이 변경되면 SleepQualityFragment로 이동한다. SleepTrackerFragment
viewModel.navigateToSleepQuality.observe(viewLifecycleOwner, Observer { night ->
night?.let {
this.findNavController().navigate(
SleepTrackerFragmentDirections
.actionSleepTrackerFragmentToSleepQualityFragment(night.nightId))
viewModel.doneNavigating()
}
})
관찰하고 있던 navigateToSleepQuality의 값은 STOP에서 넣어줬던 oldNight 객체이다. 그 객체의 Id를 넘겨서 해당 id 사용해서 컬럼의 sleepQuality를 입력하고 update 해야하기 때문에 필요하다.
SleepQualityFragment를 사용하기 위해 SleepQualityViewModel을 만든다.
SleepTrackerFragment에서 넘겨준 key와 databaseDao를 사용하기 위해 viewModelProvider 를 만들어준다.
SleepQualityViewModelFactory
class SleepQualityViewModelFactory(private val sleepNightKey:Long = 0L,
private val dataSource: SleepDatabaseDao):ViewModelProvider.Factory{
@Suppress("uncheked_cast")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if(modelClass.isAssignableFrom(SleepQualityViewModel::class.java)){
return SleepQualityViewModel(sleepNightKey,dataSource) as T
}
throw IllegalArgumentException("Unkown ViewModel Class")
}
}
만들어준 viewModelFactory를 사용해서 viewModel을 만들어준다.
SleepQualityFragment
class SleepQualityFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Get a reference to the binding object and inflate the fragment views.
val binding: FragmentSleepQualityBinding = DataBindingUtil.inflate(
inflater, R.layout.fragment_sleep_quality, container, false)
//SleepTrackerFragment에서 넘겨준 값
val arguments = SleepQualityFragmentArgs.fromBundle(requireArguments())
//Database객체를 얻어올때 사용되는 application val application = requireNotNull(this.activity).application
//Dao
val dataSource = SleepDatabase.getInstance(application).sleepDatabaseDao
//넘겨받은 키값과 dao를 사용해 viewModelProvider 생성
val viewModelProvider = SleepQualityViewModelFactory(arguments.sleepNightKey,dataSource)
//만든 viewModelProvider를 사용해서 viewModel 생성
val viewModel = ViewModelProvider(this,viewModelProvider).get(SleepQualityViewModel::class.java)
//바인딩
binding.viewModel = viewModel
binding.lifecycleOwner = viewLifecycleOwner
return binding.root
}
}
SleepTrackerFragment로 부터 넘겨받은 id와 Dao객체로 viewModelProvider가 만들어졌고, viewModelProvider로 viewModel도 만들었다. 그리고 데이터바인딩도 해줬다.
SleepQualityFragment에서 Quality를 선택하고 다시 SleepTrackerFragment로 넘어가야하기 때문에
viewModel에 다음 코드를 추가해준다.
private val _navigateToSleepTracker = MutableLiveData<Boolean?>()
val navigateToSleepTracker : LiveData<Boolean?>
get() = _navigateToSleepTracker
fun doneNavigating() {
_navigateToSleepTracker.value = null
}
fun onSetSleepQuality(quality:Int){
viewModelScope.launch {
val tonight = database.get(sleepNightKey) ?: return@launch
tonight.sleepQuality = quality
database.update(tonight)
_navigateToSleepTracker.value = true
}
}
SleepQualityFragment에서 navigateToSleepTracker를 관찰하고 있다가 Quailty를 선택하면 _navigateToSleepTracker.value = true가 되면서 다시 SleepTrackerFragment로 돌아간다.
viewModel.navigateToSleepTracker.observe(viewLifecycleOwner, Observer {
if (it == true) { // Observed state is true.
this.findNavController().navigate(
SleepQualityFragmentDirections.actionSleepQualityFragmentToSleepTrackerFragment())
viewModel.doneNavigating()
}})
Comments