일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- ar vr 차이
- jvm이란
- 멤버변수
- jvm 작동 원리
- 안드로이드 레트로핏 crud
- 안드로이드 라이선스
- 플러터 설치 2022
- 안드로이드 유닛테스트란
- 자바 다형성
- android ar 개발
- 안드로이드 os 구조
- 안드로이드 유닛 테스트 예시
- 안드로이드 라이선스 종류
- Rxjava Observable
- rxjava cold observable
- 큐 자바 코드
- rxjava hot observable
- 서비스 쓰레드 차이
- ANR이란
- android retrofit login
- 스택 큐 차이
- 서비스 vs 쓰레드
- 2022 플러터 설치
- rxjava disposable
- 스택 자바 코드
- 안드로이드 레트로핏 사용법
- 2022 플러터 안드로이드 스튜디오
- 안드로이드 유닛 테스트
- 객체
- 클래스
- Today
- Total
나만을 위한 블로그
[Android] Jetpack Navigation, Room DB, Flow 같이 사용하기 - 2 - 본문
이전 글에서 Room을 사용하기 위한 기본 준비들을 모두 끝냈으니 이제 Room을 사용하기 위한 뷰모델을 만들고 프래그먼트에 실제로 사용한다. 이전 글은 아래 링크를 타고 이동하면 볼 수 있다.
https://onlyfor-me-blog.tistory.com/556
data 패키지 바깥에 InventoryViewModel 클래스를 만든다. 그리고 ItemDao 객체를 매개변수로 기본 생성자에 전달하게 한다.
import androidx.lifecycle.*
import com.example.kotlinprac.room.data.Item
import com.example.kotlinprac.room.data.ItemDao
import kotlinx.coroutines.launch
import kotlin.coroutines.coroutineContext
class InventoryViewModel(
private val itemDao: ItemDao
): ViewModel() {
}
그리고 클래스 맨 밑에 InventoryViewModelFactory 클래스를 만든다. 마찬가지로 ItemDao를 기본 생성자로 넘겨야 한다.
그리고 ViewModelProvider.Factory 인터페이스를 구현하고 create()를 재정의한다.
import androidx.lifecycle.*
import com.example.kotlinprac.room.data.Item
import com.example.kotlinprac.room.data.ItemDao
import kotlinx.coroutines.launch
import kotlin.coroutines.coroutineContext
class InventoryViewModel(
private val itemDao: ItemDao
): ViewModel() {
}
class InventoryViewModelFactory(
private val itemDao: ItemDao
): ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
require(modelClass.isAssignableFrom(InventoryViewModel::class.java)) {
throw IllegalArgumentException("Unknown ViewModel class")
}
@Suppress("UNCHECKED_CAST")
return InventoryViewModel(itemDao) as T
}
}
이제 AddItemFragment에 이것저것 입력하고 save 버튼을 누르면 Room DB에 내용이 저장되게 한다. 먼저 뷰모델에 insertItem()을 만든다.
import androidx.lifecycle.*
import com.example.kotlinprac.room.data.Item
import com.example.kotlinprac.room.data.ItemDao
import kotlinx.coroutines.launch
import kotlin.coroutines.coroutineContext
class InventoryViewModel(
private val itemDao: ItemDao
): ViewModel() {
private fun insertItem(item: Item) {
viewModelScope.launch {
itemDao.insert(item)
}
}
}
class InventoryViewModelFactory(
private val itemDao: ItemDao
): ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
require(modelClass.isAssignableFrom(InventoryViewModel::class.java)) {
throw IllegalArgumentException("Unknown ViewModel class")
}
@Suppress("UNCHECKED_CAST")
return InventoryViewModel(itemDao) as T
}
}
insertItem()의 매개변수로 넘길 Item 객체를 만들기 위해 문자열 3개를 가져와서 Item 인스턴스를 반환하는 private 함수를 만든다.
class InventoryViewModel(
private val itemDao: ItemDao
): ViewModel() {
private fun insertItem(item: Item) {
viewModelScope.launch {
itemDao.insert(item)
}
}
private fun getNewItemEntry(itemName: String, itemPrice: String, itemCount: String): Item =
Item(
itemName = itemName,
itemPrice = itemPrice.toDouble(),
quantityInStock = itemCount.toInt()
)
}
class InventoryViewModelFactory(
private val itemDao: ItemDao
): ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
require(modelClass.isAssignableFrom(InventoryViewModel::class.java)) {
throw IllegalArgumentException("Unknown ViewModel class")
}
@Suppress("UNCHECKED_CAST")
return InventoryViewModel(itemDao) as T
}
}
계속해서 방금 만든 getNewItemEntry()에 넣을 문자열 3개를 가져오는 addNewItem()과 을 만든다. 이 함수의 내부에서 insertItem()을 호출해서 Room DB에 아이템을 넣을 수 있게 하고, 호출은 프래그먼트에서 할 것이다.
class InventoryViewModel(
private val itemDao: ItemDao
): ViewModel() {
private fun insertItem(item: Item) {
viewModelScope.launch {
itemDao.insert(item)
}
}
private fun getNewItemEntry(itemName: String, itemPrice: String, itemCount: String): Item =
Item(
itemName = itemName,
itemPrice = itemPrice.toDouble(),
quantityInStock = itemCount.toInt()
)
fun addNewItem(itemName: String, itemPrice: String, itemCount: String) {
val newItem = getNewItemEntry(itemName, itemPrice, itemCount)
insertItem(newItem)
}
fun isEntryValid(itemName: String, itemPrice: String, itemCount: String): Boolean {
if (itemName.isBlank() || itemPrice.isBlank() || itemCount.isBlank()) {
return false
}
return true
}
}
class InventoryViewModelFactory(
private val itemDao: ItemDao
): ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
require(modelClass.isAssignableFrom(InventoryViewModel::class.java)) {
throw IllegalArgumentException("Unknown ViewModel class")
}
@Suppress("UNCHECKED_CAST")
return InventoryViewModel(itemDao) as T
}
}
이제 AddItemFragment로 이동해서 아이템을 추가할 수 있게 뷰모델 참조 객체를 만들고 함수를 호출한다. 전체 코드는 아래와 같다.
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.TextView
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import com.example.kotlinprac.R
import com.example.kotlinprac.databinding.FragmentAddItemBinding
import com.example.kotlinprac.room.data.Item
class AddItemFragment : Fragment() {
private val navigationArgs: ItemDetailFragmentArgs by navArgs()
// by activityViewModels {} : 속성 위임을 써서 프래그먼트 전체에서 뷰모델을 공유하게 함
private val viewModel: InventoryViewModel by activityViewModels {
InventoryViewModelFactory((activity?.application as InventoryApplication).database.itemDao())
}
lateinit var item: Item
private var _binding: FragmentAddItemBinding? = null
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentAddItemBinding.inflate(inflater, container, false)
return binding.root
}
private fun isEntryValid(): Boolean {
return viewModel.isEntryValid(
binding.itemName.text.toString(),
binding.itemPrice.text.toString(),
binding.itemCount.text.toString()
)
}
private fun addNewItem() {
if (isEntryValid()) {
viewModel.addNewItem(
binding.itemName.text.toString(),
binding.itemPrice.text.toString(),
binding.itemCount.text.toString()
)
val action = AddItemFragmentDirections.actionAddItemFragmentToItemListFragment()
findNavController().navigate(action)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.saveAction.setOnClickListener {
addNewItem()
}
}
override fun onDestroyView() {
super.onDestroyView()
// 키보드 숨기기
val inputMethodManager = requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as
InputMethodManager
inputMethodManager.hideSoftInputFromWindow(requireActivity().currentFocus?.windowToken, 0)
_binding = null
}
}
svae 버튼의 클릭 리스너를 만들고 addNewItem()을 연결한다. 실행해서 아이템을 추가해 본다.
추가됐는지 확인하려면 안드로이드 스튜디오 메뉴 중 View > Tool Windows > App Inspection을 누르고 Database Inspector를 선택한다. 그리고 Live updates 체크박스를 체크하고 다시 데이터를 넣어보면 실시간으로 DB에 데이터가 들어가는 걸 볼 수 있다.
'Android' 카테고리의 다른 글
[Android] Jetpack Navigation, Room DB, Flow 같이 사용하기 - 4 - (0) | 2022.12.13 |
---|---|
[Android] Jetpack Navigation, Room DB, Flow 같이 사용하기 - 3 - (0) | 2022.12.13 |
[Android] Flow vs LiveData (0) | 2022.12.12 |
[Android] Jetpack Navigation, Room DB, Flow 같이 사용하기 - 1 - (0) | 2022.12.12 |
[Android] Navigation 사용 시 FragmentDirections가 자동 생성되지 않을 때 (0) | 2022.12.09 |