1. Hilt를 사용하는 어플이므로 application클래스에
@HiltAndroidApp
class MainApplication : Application()
HiltAndroidApp를 붙여준다.
2. Application클래스에 Hilt를 붙여주고 다른 Android 클래스에 AndroidEntryPoint를 붙여주면 종속항목을 제공할 수 있다.
@AndroidEntryPoint
class GardenFragment : Fragment()
{..}
위와 같이 안드로이드 클래스에 주석을 사용하게 되면 위의 클래스를 사용하는 클래스에서도 주석을 작성해야 함
위의 프래그먼트를 사용하는 액티비티에도 위와 같은 주석이 있어야 함
3. 아래의 뷰모델의 객체가 생성되는 부분이 oncreateView에도 없다. Dagger을 생각해보면 @Inject 같은 주석을 달아서 필드 삽입을 해야 될 것 같은데 앞에 붙은 주석도 없다. 이건 Hilt로 viewModel도 지원을 하게 되면서 생겼다고 함. 원래 ViewModel에 @ViewModelInject를 주석을 달면서 사용을 하는데 이 기능이 중단되면서 @HiltViewModel이라는 주석을 달게 됨.
@AndroidEntryPoint
class GardenFragment : Fragment() {
private lateinit var binding: FragmentGardenBinding
private val viewModel: GardenPlantingListViewModel by viewModels()
...
}
ViewModel을 주석을 달아서 작성하게 되면 @AndroidEntryPoint가 달린 액티비티나 프래그먼트에 ViewModelProvider 또는 by viewModels()를 사용하여 인스턴스를 가져올 수 있다.
4. 뷰 모델을 한 번 확인해 보자!
@HiltViewModel
class GardenPlantingListViewModel @Inject internal constructor(
gardenPlantingRepository: GardenPlantingRepository
) : ViewModel() {
val plantAndGardenPlantings: LiveData<List<PlantAndGardenPlantings>> =
gardenPlantingRepository.getPlantedGardens().asLiveData()
}
gardenPlantingRepository가 생성자로 Inject 되어있다. 그리고 PlantAndGardenPlantings라는 클래스를 라이브 데이터로 위의 Repository에서 받아오도록 되어있다.
그럼 우선 PlantAndGardenPlantings를 보고 Repository를 보겠음.
data class PlantAndGardenPlantings(
@Embedded
val plant: Plant,
@Relation(parentColumn = "id", entityColumn = "plant_id")
val gardenPlantings: List<GardenPlanting> = emptyList()
)
내가 기대한 data class의 형태는
@Entity(tableName = "plants")
data class Plant(
@PrimaryKey @ColumnInfo(name = "id") val plantId: String,
val name: String,
val description: String,
val growZoneNumber: Int,
val wateringInterval: Int = 7, // how often the plant should be watered, in days
val imageUrl: String = ""
)
이런 형태였는데 Embedded 와 Relation이 나왔다..
Embedded (Room) 이건 대체 뭔가?
데이버 베이스에서 각 개체 모델로 관계를 매핑하는 것이 일반적이고, 서버에서는 잘 작동하지만 클라이언트 측에서는 지연 로드가 UI스레드에서 작동하기 때문에 아주 짧은 순간이 쿼리에 걸릴지라도 시각적 결함이 생긴다고 한다. 그래서 Room은 상호 참조를 명시적으로 금지한다고 함
그러니까 데이터 베이스의 개체마다의 관계를 1:1 이든 다:다든 만들 수가 있는데
data class Address(
val street: String?,
val state: String?,
val city: String?,
@ColumnInfo(name = "post_code") val postCode: Int
)
@Entity
data class User(
@PrimaryKey val id: Int,
val firstName: String?,
@Embedded val address: Address?
)
이런 식으로 User 클래스가 Address의 클래스를 포함하는 관계로 만들 수 있다는 것?
일반적으로 내가 사용했던 primary key는 이를 통해 1:1 관계를 만드는 데이터 베이스 형태였음. 1:1 데이터 베이스 말고 사용할 경우가 많이 없었던 거 같은데 적용해봐야지.
Relation은 1:1 관계의 두 데이터 클래스의 관계를 연결해줌
다시 gardenPlantingRepository에서 보면
Plant 데이터 클래스와 GardenPlanting 데이터 클래스의 id와 plant_id의 관계를 연결해 주고 새로운 PlantAndGardenPlantings 데이터 클래스를 만들어 준 것임.
무슨 말인지 잘 모르겠으니 나중에 데이터 클래스 자세히 볼 때 알아보겠음.
그럼 inject 돼있는 gardenPlantingRepository를 보자!
@Singleton
class GardenPlantingRepository @Inject constructor(
private val gardenPlantingDao: GardenPlantingDao
) {
suspend fun createGardenPlanting(plantId: String) {
val gardenPlanting = GardenPlanting(plantId)
gardenPlantingDao.insertGardenPlanting(gardenPlanting)
}
suspend fun removeGardenPlanting(gardenPlanting: GardenPlanting) {
gardenPlantingDao.deleteGardenPlanting(gardenPlanting)
}
fun isPlanted(plantId: String) =
gardenPlantingDao.isPlanted(plantId)
fun getPlantedGardens() = gardenPlantingDao.getPlantedGardens()
}
GardenPlantingDao는 Gardenplanting 데이터 클래스에 접근할 수 있도록 만든 오브잭트임
볼만 한 것은 @Singleton 주석을 이용해서 Repository가 존재하고 있을 동안에는 하나만 존재하도록 만드는 것임
다시 Fragment 단으로 보면
@AndroidEntryPoint
class GardenFragment : Fragment() {
private lateinit var binding: FragmentGardenBinding
private val viewModel: GardenPlantingListViewModel by viewModels()
private fun subscribeUi(adapter: GardenPlantingAdapter, binding: FragmentGardenBinding) {
viewModel.plantAndGardenPlantings.observe(viewLifecycleOwner) { result ->
binding.hasPlantings = !result.isNullOrEmpty()
adapter.submitList(result)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
...
subscribeUi(adapter, binding)
...
}
...
}
이렇게 viewModel을 사용한다. 근데 observe가 deprecated 가 된다고 하니 업데이트를 나중에 확인해봐야 함
다음에는 viewModel을 이용해서 가져온 Live Data를 어떻게 사용하여 어댑터에 넣는지와 될 수 있으면 Flow까지 공부해 보고 싶다
'안드로이드 jetpack > sunflower' 카테고리의 다른 글
6.liveData를 사용해 보자(Viewmodel 적용기) (0) | 2021.05.04 |
---|---|
5. work에 대해서 알아보자 (0) | 2021.05.02 |
4. Paging, PagingAdapter (0) | 2021.05.02 |
3.recyclerview(ListAdapter) (0) | 2021.05.02 |
1. DI 종속성 주입 (sunflower 분석 ,hilt, dagger) (0) | 2021.04.29 |