๊ฐœ๋ฐœ ์ผ์ง€ ๐Ÿ’ป/Nutri Capture

Nutri Capture ํ”„๋ก ํŠธ์—”๋“œ - ๋ฌดํ•œ ์Šคํฌ๋กค ๋กœ์ง ๋ถ„๋ฆฌ

interfacer_han 2024. 10. 12. 05:20

#1 ๊ฐœ์š”

์ด์ „ ๊ฒŒ์‹œ๊ธ€์—์„  ๋ถˆ์™„์ „ํ•œ ๋ฌดํ•œ ์Šคํฌ๋กค์„ ๊ตฌํ˜„ํ–ˆ์—ˆ๋‹ค. ๊ทธ ๋ถˆ์™„์ „ํ•จ์„ ๋ณด์™„ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์•ž์„œ, ๋จผ์ € ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ๊ตํ†ต ์ •๋ฆฌํ•˜๊ฒ ๋‹ค. ์ฒซ์งธ๋กœ๋Š” ์ดˆ๊ธฐ ํ™”๋ฉด์—์„œ ๋ณด์ผ Item์„ ํ•˜๋‚˜์—์„œ 20๊ฐœ๋กœ ๋Š˜๋ฆฐ๋‹ค. ์ดˆ๊ธฐ Item์ด ํ•˜๋‚˜ ๋ฟ์ด๋ฉด ์•„๋žซ ๋ฐฉํ–ฅ ๋ฌดํ•œ ์Šคํฌ๋กค ๋กœ์ง๊ณผ ์—ญ๋ฐฉํ–ฅ(์œ— ๋ฐฉํ–ฅ) ๋ฌดํ•œ ์Šคํฌ๋กค ๋กœ์ง์ด ๋™์‹œ์— ์ž‘๋™ํ•˜๊ธฐ์— ์ด๋ฅผ ์ง๊ด€์ ์œผ๋กœ ๋‹ค๋ฃจ๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. 20๊ฐœ๋ผ๋Š” ์ˆซ์ž๋Š” Item๋“ค์ด ํ™”๋ฉด์„ ๊ฐ€๋“ ์ฑ„์šธ๋งŒํ•œ ์•„๋ฌด ์ˆซ์ž๋‹ค. ํŠน์ • ์ˆซ์ž๋กœ ํ•˜๋“œ ์ฝ”๋”ฉํ•˜๋Š” ๊ฒŒ ์ฉ ๋‚ดํ‚ค์ง€๋Š” ์•Š์ง€๋งŒ, ์ผ๋‹จ ์ง€๊ธˆ์€ ๋ฌดํ•œ ์Šคํฌ๋กค์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒŒ ๊ธ‰์„ ๋ฌด๋‹ค. ๋‚˜์ค‘์— ์†Œํ”„ํŠธ ์ฝ”๋”ฉ์œผ๋กœ ๋ฐ”๊พธ๊ฒ ๋‹ค.

 

๋˜, ๋ฌดํ•œ ์Šคํฌ๋กค ๋กœ์ง์ด ์ดˆ๊ธฐํ™”๊ฐ€ ์™„์ „ํžˆ ์™„๋ฃŒ๋œ ํ›„์— ์ž‘๋™ํ•˜๋„๋ก ๋งŒ๋“ค ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ๋ทฐ ๋ชจ๋ธ์— ์ดˆ๊ธฐํ™” ์™„๋ฃŒ ์ •๋ณด๋ฅผ ๋‹ด๋Š” Booleanํ˜• ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•  ๊ฒƒ์ด๋‹ค.

 

#2 ์ฝ”๋“œ

#2-1 ViewModel์— isInitialized ํ”„๋กœํผํ‹ฐ ์„ ์–ธ

...

class NutrientViewModel : ViewModel() {
    // (1) ํ™”๋ฉด ํ‘œ์‹œ์šฉ State
    ...

    // (2) ViewModel์šฉ ๋‚ด๋ถ€ ๋ณ€์ˆ˜
    private val _isInitialized = mutableStateOf(false)
    val isInitialized: State<Boolean>
        get() = _isInitialized

    // (3) View์—์„œ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•  ์ด๋ฒคํŠธ
    ...

    // (4) View๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
    fun onEvent(event: NutrientViewModelEvent) {
        ...
    }
}

State๋กœ ์„ ์–ธํ•ด์•ผ Jetpack Compose Runtime์ด ๊ฐ’์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. (1) ํ™”๋ฉด ํ‘œ์‹œ์šฉ State์— isInitialized๋ฅผ ๋„ฃ์ง€ ์•Š์€ ์ด์œ ๋Š” (1)์—๋Š” ๋ˆˆ์— ๋ณด์ด๋Š” UI์— ๊ด€๋ จ๋œ ๊ฒƒ๋งŒ ๋„ฃ๊ธฐ๋กœ ๊ทœ์น™์„ ์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋งˆ์น˜ ์‚ฌ์ง„๋“ค์„ ์นดํ…Œ๊ณ ๋ฆฌ ๋ณ„๋กœ ๋‚˜๋ˆ  ๊ฐ๊ฐ์˜ ์•จ๋ฒ”์— ๋ถ„๋ฅ˜ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ๋ง์ด๋‹ค. isInitialized๋Š” ์‚ฌ์šฉ์ž์˜ ๋ˆˆ์— ๋ณด์ด์ง€ ์•Š๋Š” ๋‚ด๋ถ€์ ์ธ ๋™์ž‘์— ๊ด€๋ จ๋œ ํ”„๋กœํผํ‹ฐ๊ณ , ์•ž์œผ๋กœ๋„ ์ด์™€ ์œ ์‚ฌํ•œ ํ”„๋กœํผํ‹ฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด (2)์˜ ์˜์—ญ์— ์„ ์–ธํ•˜๊ธฐ๋กœ ํ•œ๋‹ค.

 

#2-2 LazyColumn์—์„œ ํ‘œ์‹œํ•  ์•„์ดํ…œ์˜ ์ดˆ๊ธฐ ๊ฐฏ์ˆ˜๋ฅผ 1๊ฐœ์—์„œ 20๊ฐœ๋กœ ๋ณ€๊ฒฝ

...

class NutrientViewModel : ViewModel() {
    // (1) ํ™”๋ฉด ํ‘œ์‹œ์šฉ State
    ...

    // (2) ViewModel์šฉ ๋‚ด๋ถ€ ๋ณ€์ˆ˜
    ...

    // (3) View์—์„œ ๋ฐ›์•„ ์ฒ˜๋ฆฌํ•  ์ด๋ฒคํŠธ
    ...

    // (4) View๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
    fun onEvent(event: NutrientViewModelEvent) {
        when (event) {
            is NutrientViewModelEvent.InitializeState -> {
                var dateToInsert = LocalDate.now()
                repeat(20) {
                    _nutrientScreenState.value.dailyMeals.add(
                        DailyMeal(
                            date = dateToInsert,
                            meals = SnapshotStateList()
                        )
                    )
                    dateToInsert = dateToInsert.plusDays(1)
                }
                _isInitialized.value = true
            }

            ...
        }
    }
}

add() ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ๋ฐฉ๊ธˆ ๋งŒ๋“ค์—ˆ๋˜ isInitialized์— true๋ฅผ ํ• ๋‹นํ•œ๋‹ค.

 

#2-3 LaunchedEffect ๋ถ„๋ฆฌ

...

@Composable
fun NutrientScreen(
    ...
) {
    ...

    LaunchedEffect(key1 = true) {
        // State ์ดˆ๊ธฐํ™”
        ...

        // ViewModel๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
        viewModel.nutrientScreenEventFlow.collectLatest { ... ->
            ...
        }
    }

    LaunchedEffect(key1 = viewModel.isInitialized.value) {
        if(viewModel.isInitialized.value) {
            // ๋ฌดํ•œ ์Šคํฌ๋กค
            snapshotFlow { ... }.collect { ... ->
                ...
            }
        }
    }

    LazyColumn(
        ...
    ) {
        ...
    }
}

LaunchedEffect๋ฅผ 2๊ฐœ๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค. ์ƒˆ๋กœ ๋งŒ๋“  LaunchedEffect์— ๋ฌดํ•œ ์Šคํฌ๋กค ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ์˜ฎ๊ฒจ ๋„ฃ๋Š”๋‹ค. ์ƒˆ๋กœ ๋งŒ๋“  LaunchedEffect์˜ key๋Š” ์•„๊นŒ ๋งŒ๋“  isInitialized์˜ value๋ฅผ ๋„ฃ๊ณ  ํ•ด๋‹น ๊ฐ’์ด true์ผ๋•Œ๋งŒ ๋‚ด์šฉ๋ฌผ์ด ๋™์ž‘ํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ, ์ดˆ๊ธฐํ™”๊ฐ€ ์™„๋ฃŒ๋˜์–ด์•ผ ๋น„๋กœ์†Œ ๋ฌดํ•œ ์Šคํฌ๋กค์ด ์ž‘๋™ํ•œ๋‹ค. ์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ์ง€๊ธˆ์œผ๋กœ์„  ํฐ ์˜๋ฏธ๊ฐ€ ์—†์–ด๋ณด์ด์ง€๋งŒ, ๋ถ„๋ช… ์ž ์žฌ์ ์ธ ์—๋Ÿฌ๋ฅผ ์ค„์—ฌ์ค„ ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•œ๋‹ค. 

 

#3 ์š”์•ฝ

๋ฌดํ•œ ์Šคํฌ๋กค ๋กœ์ง์ด ์ดˆ๊ธฐํ™” ์ดํ›„ ์ž‘๋™ํ•˜๋„๋ก ๋ณ€๊ฒฝํ–ˆ๋‹ค.

 

#4 ์™„์„ฑ๋œ ์•ฑ

#4-1 ์ด ๊ฒŒ์‹œ๊ธ€ ์‹œ์ ์˜ Commit

 

GitHub - Kanmanemone/nutri-capture-new

Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.

github.com

 

#4-2 ๋ณธ ํ”„๋กœ์ ํŠธ์˜ ๊ฐ€์žฅ ์ตœ์‹  Commit

 

GitHub - Kanmanemone/nutri-capture-new

Contribute to Kanmanemone/nutri-capture-new development by creating an account on GitHub.

github.com