Nutri Capture ํ๋ก ํธ์๋ - ์ญ๋ฐฉํฅ ๋ฌดํ ์คํฌ๋กค
#1 ๊ฐ์
์ด์ ๊ฒ์๊ธ์์ ์ญ๋ฐฉํฅ ๋ฌดํ ์คํฌ๋กค์ ๋ถ์์ ํ๊ฒ ๊ตฌํํ์๋ค. ๋ฌธ์ ์ ์ ๋ค์๊ณผ ๊ฐ์๋ค.
1
๋์ ๋ณด์ด๋ Item์ ์ธ๋ฑ์ค ์ค 0์ด ์กด์ฌํ๋ฉด, ์๋ก์ด Item์ Loadํ๋ค.
2
์ด๋ฌ๋ฉด ์๋ก Load๋ Item์ ์ธ๋ฑ์ค๊ฐ ๋ค์ 0์ด๋๋ฉด์ ๋์์ ๋์ ๋ณด์ด๊ฒ ๋๋ค. ๋ฐ๋ผ์ ๋ฌดํ ์ฌ๊ทํธ์ถ์ด ๋ฐ์ํ์๋ค.
3
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ์ Item์ Loadํจ๊ณผ ๋์์ ์คํฌ๋กค์ ์กฐ์ํด์ผ ํ๋ค. ๊ทธ๋ ๊ฒ ํด์ '์ ์์ดํ ์ด ๋์ ๋ณด์ด๊ธฐ ์ ์' ์คํฌ๋กค์ ์ฑ๊ณต์ํจ๋ค๋ฉด ๋ฌดํ ์ฌ๊ทํธ์ถ์์ ๋ฒ์ด๋ ์ ์๋ค.
๋ณธ ๊ฒ์๊ธ์์ 3 ์ ์ํ๋ฅผ ๋ง๋๋ ๊ฑธ ๋ชฉํ๋ก ์ก๋๋ค.
#2 ์ฝ๋
#2-1 ๊นจ์ ๋ณ๊ฒฝ
...
@Composable
fun NutrientScreen(
scope: CoroutineScope,
snackbarHostState: SnackbarHostState,
viewModel: NutrientViewModel = viewModel<NutrientViewModel>(),
listState: LazyListState = rememberLazyListState()
) {
...
}
ํ๋กํผํฐ listState์ ์์น๋ฅผ ์์ฑ์๋ก ์ฎ๊ฒผ๋ค. ์ด ํธ์ด ๋ ๊น๋ํด๋ณด์๊ธฐ ๋๋ฌธ์ด๋ค.
#2-2 ์ด๋ฒคํธ ์ ์ธ
// package com.example.nutri_capture_new.nutrient
sealed class NutrientScreenEvent {
...
data class ScrollToItem(val index: Int) : NutrientScreenEvent()
}
ViewModel.onEvent()์ ์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate๊ฐ ์ธ์๋ก์ ์ ๋ฌ๋๋ฉด, LazyColumn์ด ํ์ํ ์์ดํ ๋ฆฌ์คํธ์ ์ ๋ถ๋ถ์ ์ Item์ ๋ฃ์ด์ฃผ์๋ค. ์ Item์ ๋ฃ์ ์งํ์ #1์์ ๋งํ ์คํฌ๋กค ์์ ์ View์ ์์ฒญํด์ผ ํ๋ค. ํด๋น ์์ฒญ์ ์ํ ์ด๋ฒคํธ๋ฅผ ์ ์ธํ๋ค.
#2-3 ์ด๋ฒคํธ ๊ตฌํ
...
class NutrientViewModel : ViewModel() {
...
// (4) View๋ก๋ถํฐ ๋ฐ์ ์ด๋ฒคํธ ์ฒ๋ฆฌ
fun onEvent(event: NutrientViewModelEvent) {
when (event) {
...
is NutrientViewModelEvent.LoadMoreItemsBeforeFirstDate -> {
Log.i("interfacer_han", "(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ์์ (์์ดํ
๊ฐฏ์: ${_nutrientScreenState.value.dailyMeals.size})")
val firstDate = _nutrientScreenState.value.dailyMeals.first().date
_nutrientScreenState.value.dailyMeals.add(
0,
DailyMeal(
date = firstDate.minusDays(1),
meals = SnapshotStateList()
)
)
Log.i("interfacer_han", "(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ๋ (์์ดํ
๊ฐฏ์: ${_nutrientScreenState.value.dailyMeals.size})")
viewModelScope.launch {
Log.i("interfacer_han", "(์ด๋ฒคํธ ScrollToItem) ํธ์ถ")
_nutrientScreenEventFlow.emit(NutrientScreenEvent.ScrollToItem(1))
}
}
}
}
}
viewModelScope์์ StateFlow.emit()์ ์ํํ๋ค. ๋์ง๋์ง ๋ถ์ด์๋ Log๋ฌธ์ ํจ์ ํธ์ถ ์์๋ฅผ ํ์ ํ๊ธฐ ์ํจ์ด๋ค. #1์์ '์ ์์ดํ ์ด ๋์ ๋ณด์ด๊ธฐ ์ ์' ์คํฌ๋กค์ด ์๋ฃ๋์ด์ผ ํ๋ค๊ณ ํ๋๋ฐ, ํ ํ๋ก์ ํธ์ฒ๋ผ ๋น๋๊ธฐ ์ฝ๋๊ฐ ๋ง์ด ์ฐ์ธ ํ๋ก์ ํธ์ ๊ฒฝ์ฐ ๋ด๊ฐ ์๋ํ ์์๋๋ก ์ค์ ์ฑ์ด ์๋ํ์ง ์์ ์ ์๋ค. ๋ฐ๋ผ์ Log์ ํตํด ํจ์ ํธ์ถ ์์๋ฅผ ๋ช ํํ ์์๋์ด์ผ ํ๋ค.
#2-4 ์ด๋ฒคํธ ๋ฐ๊ธฐ
...
@Composable
fun NutrientScreen(
...
) {
LaunchedEffect(key1 = true) {
// State ์ด๊ธฐํ
...
// ViewModel๋ก๋ถํฐ ๋ฐ์ ์ด๋ฒคํธ ์ฒ๋ฆฌ
viewModel.nutrientScreenEventFlow.collectLatest { event ->
when (event) {
...
is NutrientScreenEvent.ScrollToItem -> {
Log.i("interfacer_han", "(์ด๋ฒคํธ ScrollToItem) ์์ (์์ดํ
๊ฐฏ์: ${viewModel.nutrientScreenState.value.dailyMeals.size})")
listState.scrollToItem(event.index)
Log.i("interfacer_han", "(์ด๋ฒคํธ ScrollToItem) ๋ (์์ดํ
๊ฐฏ์: ${viewModel.nutrientScreenState.value.dailyMeals.size})")
}
}
}
}
LaunchedEffect(key1 = viewModel.isInitialized.value) {
...
}
LazyColumn(
...
) {
val dailyMeals = viewModel.nutrientScreenState.value.dailyMeals
Log.i("interfacer_han", "(LazyColumn Recomposition) ์์ดํ
๊ฐฏ์: ${dailyMeals.size}")
items(...) { ... ->
...
}
}
}
View์์ ์ด๋ฒคํธ๋ฅผ ๋ฐ๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก Log๋ฌธ์ ๋ถ์ฌ์ค๋ค. ๋, Recomposition ํ์ด๋ฐ๋ ์๊ธฐ ์ํด์ LazyColumn ์ชฝ์๋ Log๋ฌธ์ ๋ฃ์๋ค.
#2-5 ๋ก๊ทธ ํ์
...
(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ํธ์ถ
(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ์์ (์์ดํ
๊ฐฏ์: 44)
(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ๋ (์์ดํ
๊ฐฏ์: 45)
(์ด๋ฒคํธ ScrollToItem) ํธ์ถ
(LazyColumn Recomposition) ์์ดํ
๊ฐฏ์: 45
(์ด๋ฒคํธ ScrollToItem) ์์ (์์ดํ
๊ฐฏ์: 45)
(์ด๋ฒคํธ ScrollToItem) ๋ (์์ดํ
๊ฐฏ์: 45)
(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ํธ์ถ
(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ์์ (์์ดํ
๊ฐฏ์: 45)
(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ๋ (์์ดํ
๊ฐฏ์: 46)
(์ด๋ฒคํธ ScrollToItem) ํธ์ถ
(LazyColumn Recomposition) ์์ดํ
๊ฐฏ์: 46
(์ด๋ฒคํธ ScrollToItem) ์์ (์์ดํ
๊ฐฏ์: 46)
(์ด๋ฒคํธ ScrollToItem) ๋ (์์ดํ
๊ฐฏ์: 46)
(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ํธ์ถ
(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ์์ (์์ดํ
๊ฐฏ์: 46)
(์ด๋ฒคํธ LoadMoreItemsBeforeFirstDate) ๋ (์์ดํ
๊ฐฏ์: 47)
(์ด๋ฒคํธ ScrollToItem) ํธ์ถ
(LazyColumn Recomposition) ์์ดํ
๊ฐฏ์: 47
(์ด๋ฒคํธ ScrollToItem) ์์ (์์ดํ
๊ฐฏ์: 47)
(์ด๋ฒคํธ ScrollToItem) ๋ (์์ดํ
๊ฐฏ์: 47)
...
์ฌ์ค ํด๋น ๋ก๊ทธ๋ ์ฑ๊ณต์ ์ผ๋ก ๋์ํ๋ ์คํฌ๋กค ์ฝ๋๋ฅผ ๋ง๋ค๊ธฐ ์ํ ๊ณผ์ ์ ๋ถ์ฐ๋ฌผ์ด๋ค. ์ด ๊ฒ์๊ธ์ ์ฐ๋ ์์ ์์๋ ์ ๋ก๊ทธ๋ค์ด ์ด๋ฏธ ์ฑ๊ณตํ ์ฝ๋์ ๋ฆฌ๋ทฐ(?)์ฒ๋ผ ๋ณด์ธ๋ค. ์ด์ฐ๋๊ฑด, ์ ๋ก๊ทธ๋ฅผ ๋ณด๋ฉด ์ Item์ ์ถ๊ฐํ๋ ์ด๋ฒคํธ์ธ LoadMoreItemsBeforeFirstDate ์ดํ LazyColumn์ Recomposition๊ณผ ScrollToItem ์ด๋ฒคํธ๊ฐ ์ํ๋๋ ๋ชจ์ต์ ํ์ธํ ์ ์๋ค. Recomposition์ด ScrollToItem ์๋ฃ๋ณด๋ค ๋ ๋จผ์ ์ํ๋๋ ๊ฒ์ฒ๋ผ ๋ก๊ทธ๊ฐ ์ถ๋ ฅ๋์์ง๋ง ์ค์ ๋ก ๋ฐ๋์ผ ๊ฒ์ด๋ค. ๋ฐ๋๋ก ์ถ๋ ฅ๋ ์ด์ ๋ ๋ก๊ทธ๋ฅผ ์ถ๋ ฅํ๋ ์์ ์ ๋ฌธ์ ์ผ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค. ๋ฌด์จ ๋ง์ด๋๋ฉด LazyColumn Recomposition์ด๋ผ๋ ๋ก๊ทธ๊ฐ ์ ๋ง LazyColumn์ด Recomposition๋๋ ์ ๋ฐํ ์์ ์ ์ถ๋ ฅ๋๋ ๊ฒ ์๋ ๊ฑฐ๋ผ๋ ์๊ธฐ๋ค. ์๋ฌดํผ, ScrollToItem์ LazyColumn์ ์์ฑ์ ์ฃผ์ ๋ LazyListState๋ฅผ ์กฐ์ํ๋ค. ๋ฐ๋ผ์, Recomposition๋๋ ์์ ์์ ํ๋ฉด์ ์ Item์ด ๊ทธ๋ ค์ง๊ธฐ ์ ์ (= ๋์ ๋ณด์ด๊ธฐ ์ ์) ์คํฌ๋กค์ด ์ํ๋๋ค.
#3 ์๋ก์ด ๋ฌธ์ ์
#3-1 ๋ฌธ์ ์ ์๋ ์์
#3-2 ๋ฌธ์ ์ ์์ธ
์ด ๋ฌธ์ ๋ ์ฌ์ฉ์์ ํฐ์น์ ์ํด ๋ฐ์ํ๋ค. ์คํฌ๋กค์ ์๋ก ์ฌ๋ฆฌ๋ ๋์์ ํ๊ธฐ ์ํด์ ์คํฌ๋กค์ 0.3์ด ์ ๋ ๋จ์๋ก ๋์ด์ ํ๋ฉด 1 ์ํ์์ 2 ์ํ๋ก ์ ์ด๋ํ๋ค. ํ์ง๋ง, ์คํฌ๋กค์ ์ ์งํ ์ฑ๋ก (= ์์ ํฐ์น ์คํฌ๋ฆฐ์์ ๋ผ์ง ์์ ์ฑ๋ก) ๊ฐ๋งํ ๋ ๋๋ฉด ์คํฌ๋กค ๊ณ ์ ์ํ๊ฐ ๋์ด #2์์ ๊ณต๋ค์ฌ ๋ง๋ ์์์ ์คํฌ๋กค ์ด๋ฒคํธ๊ฐ ๋จนํต์ด ๋์ด ๋ฒ๋ฆฐ๋ค. ๋ฐ๋ผ์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ค๋ฉด ์ฌ์ฉ์์ ์คํฌ๋กค ์์ฒญ์ ์ฐจ๋จํ๋ ๋ฐฉ์ ๋ฑ์ด ์๊ตฌ๋ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค. ๋ค์ ๊ฒ์๊ธ์์ ๋ฐ๋ก ๋ฌธ์ ํด๊ฒฐ์ ์ฐฉ์ํ๊ฒ ๋ค.
#4 ์์ฝ
๋ฌดํ ์คํฌ๋กค์ ์ผ์ผํค๋ ๊ธฐ์กด์ ๋ฌธ์ ์์ธ์ ์ ๊ฑฐํ๋ค. ํ์ง๋ง, ์๋ก์ด ๋ฌธ์ ๊ฐ ๋์๋ค.
#5 ์์ฑ๋ ์ฑ
#5-1 ์ด ๊ฒ์๊ธ ์์ ์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com
#5-2 ๋ณธ ํ๋ก์ ํธ์ ๊ฐ์ฅ ์ต์ Commit
GitHub - Kanmanemone/nutri-capture-new
Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.
github.com