이번 코드 리뷰의 코드를 작성한 팀원의 Velog입니다.
https://velog.io/@errored_pasta/WIP-Team-박카스-팀-프로젝트-2022.02.08-코드-리뷰
이 글에서는 팀원이 어떤 방법으로 기능을 구현하였는지에 대해 작성을 한 후
다음 글에서는 코드 리뷰를 진행하면서 나왔던 질문들과 답변 및 문제점으로 인한 수정부분에 대해서 작성하겠습니다.
새로운 할인 상품의 정보를 불러와서 사용자에게 출력
근처 마켓 정보를 불러와서 가까운 순으로 사용자에게 출력
카테고리별 버튼을 생성하여 클릭 시 해당 카테고리의 상품들을 출력
처음 화면(HomeMainFragment)과 상품 목록을 보여주는 화면(HomeFragment)의 이동
근처 마켓 정보와 새로운 할인 상품의 정보를 출력할 때 사용할 ViewHolder
class HomeMainViewModel(
private val homeRepository: HomeRepository
// TODO 22.01.18 add item repository
) : BaseViewModel() {
private val _marketData = MutableLiveData<HomeMainState(HomeMainState.Uninitialized)
## val marketData: LiveData<HomeMainState> = _marketData
private val _itemData = MutableLiveData<HomeMainState(HomeMainState.Uninitialized)
val itemData: LiveData<HomeMainState> = _itemData
...
override fun fetchData(): Job = viewModelScope.launch {
// get list after get location data
if (LocationData.locationStateLiveData.value is LocationState.Success) {
fetchMarketData()
fetchItemData()
}
}
...
}
HomeMainFrament에서 보여줄 근처 마켓의 정보와 새로운 할인상품을 나타낼 LiveData로 marketData 와 itemData를 Backing Property를 이용하여 데이터를 View에서 수정할 수 없도록 작성하였습니다. 처음 선언할 때 보면 Unintialized로 초기 설정을 하였고 HomeMainState의 상태가 Success가 된다면 Model들에서 데이터를 가지고 오게 하였습니다.
private suspend fun fetchMarketData() {
if (marketData.value !is HomeMainState.Success<*>
) { _marketData.value = HomeMainState.Loading
_marketData.value = HomeMainState.Success(
modelList = homeRepository.getAllMarketList().map {
it.copy(type = CellType.HOME_CELL)
}.sortedBy { it.distance }
)
}
}
fetchMarketData()는 근처의 마켓의 정보를 가지고와 거리가 가까운 순으로 정렬하는 메소드 입니다. if (marketData.value !is HomeMainState.Success<*>) 문을 활용하여 데이터가 Success가 아닐때만 정보를 가지고 오도록하여 불필요한 상황에서 데이터를 계속 불러오는 것을 방지했습니다.
private suspend fun fetchItemData() {
if (itemData.value !is HomeMainState.Success<*>
) {
_itemData.value = HomeMainState.Loading
allNewSaleItemsList = homeRepository.getAllNewSaleItems()
_itemData.value = HomeMainState.ListLoaded
}
}
fetchItemData()는 새로운 할인상품의 데이터를 불러오는 메소드입니다.
위의 fetchMarketData와 마찬가지로 데이터를 Success상태에서만 불러와 불필요한 데이터 요청을 방지했습니다.
private lateinit var allNewSaleItemsList: List<HomeItemModel>
fun setItemFilter(category: HomeListCategory) {
if (::allNewSaleItemsList.isInitialized) {
_itemData.value = HomeMainState.Success(
modelList = allNewSaleItemsList.filter {
it.homeListCategory == category
}
)
}
}
Spinner를 활용하여 새로운 할인상품에서 선택된 카테고리에 맞는 데이터를 불러온다
다음 이미지와 같이 선택할 수 있는 카테고리들이 있고 선택하면 allNewSaleItemsList에서 선택된 category에 맞는 데이터들이 modelList에 저장되고 해당되는 데이터들만 보여지게 된다.
흔히 Fragment의 화면전환은 supportFragmentManager.beginTransaction().replace() 이렇게 작성하여 마지막에 commit()을하여 많이 하였습니다. 하지만 Navigation Component를 사용하면 화면의 전환을 더욱 직관적이며 위의 명령어와 같은 Boilerplate 코드를 줄일 수 가 있습니다.
다음 이미지는 저희 프로젝트에서 작업중인 HomeFragment에 BottomNavigationView가 적용된 모습입니다. 아래 Bar에 보면 홈, 주문목록, 찜, 지도, 내 정보등의 버튼이 존재합니다.
Navigation Component에서 BottomNavigationView에서 사용하기 위해서 Navigation Graph와 BottomNavigationView의 Menu Item들을 일치시켜 주어야합니다.
그 후 Activity/Fragment에서 FragmentContainerView부분을 정해주고 navGraph 및 defaultNavHost을 설정해주고 Android Developers 공식 페이지에서는 NavHostFragment에서 NavController를 직접 가져오라고 적혀 있기에
bottomNav.setupWithNavController(navController)
이와 같이 코드를 작성해줍니다. 연결이 다된 후 다른 View를 누르게 된다면
다음과 같이 내 정보 부분이 보이게 된다.
NavigationView부분을 조금 더 자세히 작성하려다 보니 글의 내용이 많이 길어질거 같아 따로 Android 개발에 유용한 기능들을 설명하는 글을 작성할 때 해당 기능을 사용할 수 있는 방법에 대해 작성하도록 하겠습니다. 다음 글은 처음 글의 시작에 적혀있던대로 질의 및 수정 사항에 대하여 작성하도록 하겠습니다. 읽어주셔서 감사합니다.