2024. 8. 23. 03:24ㆍ카테고리 없음
# Fragment간에 Viewmodel을 통한 데이터 공유가 되지 않는 문제
- 문제 상황: FilterFragment에서 setFilter()를 통해 필터의 조건을 SharedViewModel에 저장하고,
저장한 데이터를 ItemListFragment에서 getFilteredData를 통해 반영하여 불러오는 과정에서
getFilteredData() 시 애초에 저장된 데이터 자체가 불러와지지 않고 null로 표시되는 오류가 발생함
- 문제 원인: 구글링한 결과 프래그먼트 간에 viewModels를 활용할 때에는 아래 1번의 by viewModels()가 아니라, 2번의
by activityViewModels() 를 활용해야 함 (1번의 경우 프래그먼트 내로 데이터 범위가 국한됨)
- 해결: 아래 코드 참조
// 수정 전
private val viewModel: SharedViewModel by ViewModels() {
viewModelFactory { initializer { SharedViewModel(GonggongFoodRepositoryImpl(), MarketRepositoryImpl()) } }
}
// 수정 후
private val viewModel: SharedViewModel by activityViewModels() {
viewModelFactory { initializer { SharedViewModel(GonggongFoodRepositoryImpl(), MarketRepositoryImpl()) } }
}
# List에 동적으로 값을 추가하는 과정에서 .plus()를 사용했을 때는 안되었다가 + 연산자를 사용하니까 해결
- 문제 상황: FilterFragment에서 필터링할 알러지 성분을 입력받고 입력받은 값을 selectedAllergies 리스트에 추가할 때, plus()를 사용하니 값이 제대로 추가되지 않아 IndexOutOfBoundException이 발생함
- 문제 원인: .plus(), .minus()는 기존의 값을 변경하는 것이 아니라, 변경된 새로운 값을 만드는 역할을 하는데
새로운 값을 지정해주는 게 아니라 원본 값에다 바로 .plus()를 해버리니까 원본 데이터를 그대로 빈 리스트로 남아있었던 것
- 해결: 아래 코드 참조
// 기존
egg.setOnCheckedChangeListener{ _, isChecked ->
if (isChecked) {
selectedAllergies.plus("계란")
} else {
selectedAllergies.minus("계란")
}
}
// 수정
egg.setOnCheckedChangeListener{ _, isChecked ->
if (isChecked) {
selectedAllergies += "계란"
} else {
selectedAllergies -= "계란"
}
}
# Retrofit으로 데이터를 가져올 때, null로 불러와질 경우
- 문제 상황: ItemDetailFragment에 일부 데이터가 null로 표시됨
- 문제 원인: <json> 형식의 파일을 그대로 긁어와서 json file to Kotlin 했어야 하는데 네이버 쇼핑 API 문서에 있는 xml 형식의 파일을 긁어오는 바람에 데이터클래스가 다 꼬였음.
- 해결: json 형식으로 긁어와서 다시 데이터 클래서 생성해서 해결
// 기존 xml 형식
<rss version="2.0">
<channel>
<title>Naver Open API - shop ::'가방'</title>
<link>http://search.naver.com</link>
<description>Naver Search Result</description>
<lastBuildDate>Tue, 04 Oct 2016 13:23:58 +0900</lastBuildDate>
<total>17161390</total>
<start>1</start>
<display>10</display>
<item>
<title>허니트립 보스턴백</title>
<link>http://openapi.naver.com/l?AAABWLsQ7CIBRFv+Z1JLzSShkYqLajRmPcG6TQRCgiNunfizdnODnJfX9N2iUMCnoKHYWh/4sSlUtmli7nCExBPRY+bo1xCZaEaTOJ6NWXaKdsSHAB2Lg8gZ2QMmybA0cuqiyx4W0ZZR2KrvJyx2CPV3RQ95fbnDT3r+Fh2kbfz5su7x8wIs7ZjgAAAA==</link>
<image>http://shopping.phinf.naver.net/main_1031546/10315467179.jpg</image>
<lprice>6700</lprice>
<hprice>0</hprice>
<mallName>허니트립</mallName>
<productId>10315467179</productId>
<productType>2</productType>
<brand></brand>
<maker>허니트립</maker>
<category1>패션잡화</category1>
<category2>여행용가방/소품</category2>
<category3>보스턴백</category3>
<category4></category4>
</item>
...
</channel>
</rss>
}
// 수정 json 형식
{
"lastBuildDate":"Mon, 26 Aug 2024 09:34:50 +0900",
"total":41669,
"start":1,
"display":5,
"items":[
{
"title":"롯데 <b>꼬깔콘<\/b> 고소한맛 67g",
"link":"https:\/\/search.shopping.naver.com\/catalog\/31424520970",
"image":"https:\/\/shopping-phinf.pstatic.net\/main_3142452\/31424520970.20220531161830.jpg",
"lprice":"810",
"hprice":"",
"mallName":"네이버",
"productId":"31424520970",
"productType":"1",
"brand":"롯데",
"maker":"롯데웰푸드",
"category1":"식품",
"category2":"과자\/베이커리",
"category3":"스낵",
"category4":"일반스낵"
},
{
"title":"롯데 <b>꼬깔콘<\/b> 군옥수수맛 72g",
"link":"https:\/\/search.shopping.naver.com\/catalog\/19809428787",
"image":"https:\/\/shopping-phinf.pstatic.net\/main_1980942\/19809428787.20190617152304.jpg",
"lprice":"790",
"hprice":"",
"mallName":"네이버",
"productId":"19809428787",
"productType":"1",
"brand":"롯데",
"maker":"롯데웰푸드",
"category1":"식품",
"category2":"과자\/베이커리",
"category3":"스낵",
"category4":"일반스낵"
},
{
"title":"롯데제과 봉지 과자 스낵 100종 골라담기\/새우깡 포카칩 <b>꼬깔콘<\/b>",
"link":"https:\/\/link.auction.co.kr\/gate\/pcs?item-no=C290831366&sub-id=1&service-code=10000003",
"image":"https:\/\/shopping-phinf.pstatic.net\/main_2609356\/26093566252.1.jpg",
"lprice":"900",
"hprice":"",
"mallName":"옥션",
"productId":"26093566252",
"productType":"2",
"brand":"롯데웰푸드",
"maker":"롯데웰푸드",
"category1":"식품",
"category2":"과자\/베이커리",
"category3":"스낵",
"category4":"일반스낵"
},
{
"title":"롯데 <b>꼬깔콘<\/b> 매콤달콤한맛 67g",
"link":"https:\/\/search.shopping.naver.com\/catalog\/32600420618",
"image":"https:\/\/shopping-phinf.pstatic.net\/main_3260042\/32600420618.20220526173459.jpg",
"lprice":"850",
"hprice":"",
"mallName":"네이버",
"productId":"32600420618",
"productType":"1",
"brand":"롯데",
"maker":"롯데웰푸드",
"category1":"식품",
"category2":"과자\/베이커리",
"category3":"스낵",
"category4":"일반스낵"
},
{
"title":"롯데웰푸드 <b>꼬깔콘<\/b> 고소한맛 72g",
"link":"https:\/\/search.shopping.naver.com\/catalog\/8581572484",
"image":"https:\/\/shopping-phinf.pstatic.net\/main_8581572\/8581572484.20150607225351.jpg",
"lprice":"670",
"hprice":"",
"mallName":"네이버",
"productId":"8581572484",
"productType":"1",
"brand":"롯데웰푸드",
"maker":"롯데웰푸드",
"category1":"식품",
"category2":"과자\/베이커리",
"category3":"스낵",
"category4":"일반스낵"
}
]
}
※ viewModel.observe()~~~ 를 한다는 것은, 새로 Observing한 데이터를 가지고 새로운 동작을 하려면 Observing하는 코드 안에서 이뤄져야 한다는 것을 뜻함. setonClickListener가 클릭된 이벤트와 그 이후의 동작을을 해당하는 {} 안에서 수행하듯이, viewModel.observe() 역시도 새로 받아온 데이터와, 이를 새로 UI에 반영해야 하는 동작의 경우에는 해당하는 코드 안에서 진행되어야 함.
# SignUpFragment에서 새 유저를 생성하고 SignInFragment로 넘어가서 같은 정보로 로그인하려고 하는데 존재하지 않는 아이디라고 나오는 오류
- 문제 상황: 상동
- 문제 원인: User 정보를 받아오는 UserViewModel에서 users.value에다가 값을 add만 해주고 users.value 자체를 업데이트된 값으로 재선언해주지 않아서 계속 users.value가 초기값인 null로 나왔음
- 해결: users.value에 업데이트된 값을 새로 넣어주게끔 변경함으로써 해결. 보통은 viewModel의 value값을 업데이트해줄 때에는 아래처럼 newUser과 같이 새로운 변수를 선언해주고, 그 newUser 값을 users.value에 대입하는 형식으로 업데이트를 많이 진행함.
// 기존
fun setUser(user: User) {
// _uiState.value = UiState.Loading
viewModelScope.launch {
runCatching {
_users.value.add(user)
// 보통은 변수로 LiveData.value 에 새로운 값을 써줌
// 알
// _uiState.value = UiState.Success(_homeFoods)
}.onFailure {
Log.e(TAG, "setUser() failed! : ${it.message}")
handleException(it)
// _uiState.value = UiState.Error("Error")
}
}
}
// 수정
fun setUser(user: User) {
// _uiState.value = UiState.Loading
viewModelScope.launch {
runCatching {
val newUsers = _users.value?: mutableListOf()
newUsers.add(user)
_users.value = newUsers
// 보통은 변수로 LiveData.value 에 새로운 값을 써줌
// 알
// _uiState.value = UiState.Success(_homeFoods)
}.onFailure {
Log.e(TAG, "setUser() failed! : ${it.message}")
handleException(it)
// _uiState.value = UiState.Error("Error")
}
}
}