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

Nutri Capture ๋ฐฑ์—”๋“œ - Room ๊ฐ€์ƒ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ํ•„์š”ํ•œ ๋งŒํผ๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ

interfacer_han 2024. 11. 12. 00:08

#1 ๊ฐœ์š”

#1-1 ์šฐ์•„ํ•จ

์ด์ „ ๊ฒŒ์‹œ๊ธ€์—์„œ ๋งŒ๋“ , ๊ฐ€์ƒ ํ…Œ์ด๋ธ”์„ ์ฐธ์กฐํ•˜๋Š” DAO ํ•จ์ˆ˜๋Š” ๊ฐ€์ƒ ํ…Œ์ด๋ธ”์˜ ๋ชจ๋“  ๋ ˆ์ฝ”๋“œ๋ฅผ ํ†ต์งธ๋กœ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์ด์—ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ์šฐ์•„ํ•จ๊ณผ๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ์žˆ๋Š” ๋ฐฉ์‹์ด๋‹ค. ์ฒ˜์Œ์—๋Š” ํ™”๋ฉด์„ ๊ฐ€๋“ ์ฑ„์šธ ์ •๋„์˜ ๋ ˆ์ฝ”๋“œ๋งŒ ๊ฐ€์ ธ์˜ค๊ณ , ๋ฌดํ•œ ์Šคํฌ๋กค์„ ํ†ตํ•ด์„œ ํ•„์š”ํ•œ ๋งŒํผ๋งŒ ๋˜ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์„ ๊ตฌํ˜„ํ•  ๊ฒƒ์ด๋‹ค.

 

"View๊ฐ€ ๋ณด์œ ํ•œ ๋งˆ์ง€๋ง‰ ๋ ˆ์ฝ”๋“œ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ๊ณ , ํ•ด๋‹น ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ (ํ…Œ์ด๋ธ” ์œ„์น˜ ์ƒ) ๋” ๋’ค์— ์žˆ๋Š” ๋ ˆ์ฝ”๋“œ๋“ค์„ ๋ฝ‘์•„์˜ค๋ฉด ๋  ๊ฒƒ์ด๋‹ค."๋ผ๊ณ  ์ฒ˜์Œ์—๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ๋งŒ ์ƒ๊ฐํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์‹œํ–‰์ฐฉ์˜ค๋ฅผ ๊ฒช์œผ๋ฉฐ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ ธ๋‹ค (๊ณ ์ž‘ DAO ํ•จ์ˆ˜ํ•˜๋‚˜ ๋งŒ๋“œ๋Š” ๊ฑด๋ฐ ์ด์ „ ๊ฒŒ์‹œ๊ธ€๊ณผ ๋ณ„๋„์˜ ๊ฒŒ์‹œ๊ธ€๋กœ ๋ถ„๋ฆฌํ•  ์ด์œ ๊ธฐ๋„ ํ•˜๋‹ค).

 

#1-2 ์ฒซ ์‹œ๋„: Cursor

 

Room DAO๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค  |  Android Developers

Room ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ผ๋ถ€์ธ DAO(๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค ๊ฐ์ฒด)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์„ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ• ์•Œ์•„๋ณด๊ธฐ

developer.android.com

์ œ์ผ ์ข‹์€ ๋ฐฉ๋ฒ•์€, Cursor๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์ด์ „ ๊ฒŒ์‹œ๊ธ€์—์„œ ๋งŒ๋“ค์—ˆ๋˜ ๊ฐ€์ƒ ํ…Œ์ด๋ธ”์€ ์ด 3๊ฐœ์˜ ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ ์ด๋ฏธ ์ •๋ ฌ๋œ ์ƒํƒœ์˜ ํ…Œ์ด๋ธ”์ด๊ธฐ ๋•Œ๋ฌธ์ด์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ, View๊ฐ€ ๋ณด์œ ํ•œ ๋งˆ์ง€๋ง‰ ๋ ˆ์ฝ”๋“œ์˜ ์งํ›„ ๋ ˆ์ฝ”๋“œ์— Cursor๋ฅผ ๋‘๊ณ  ํ•œ ์นธ์”ฉ ๋‚ด๋ ค๊ฐ€๋ฉฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ์‹ถ์—ˆ๋˜ ๊ฑฐ๋‹ค. ๋“ฃ๊ธฐ์—๋Š” ์ง๊ด€์ ์œผ๋กœ ๋ณด์ธ๋‹ค.

 

ํ—ˆ๋‚˜ ์œ„ ๊ณต์‹ ๋ฌธ์„œ์˜ ๊ฒฝ๊ณ ๋ฌธ์ด ๋งˆ์Œ์— ๊ฑธ๋ฆฐ๋‹ค. "Cursor API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ–‰์ด ์กด์žฌํ•˜๋Š”์ง€ ๋˜๋Š” ํ–‰์— ์–ด๋–ค ๊ฐ’์ด ๋“ค์–ด ์žˆ๋Š”์ง€ ๋ณด์žฅํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ปค์„œ๋ฅผ ์˜ˆ์ƒํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์ด๋ฏธ ์žˆ๊ณ  ์‰ฝ๊ฒŒ ๋ฆฌํŒฉํ† ๋งํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์„ธ์š”."๋ผ๋Š” ๊ฒฝ๊ณ ๋Š” ๊ดœํžˆ ์žˆ๋Š” ๊ฒŒ ์•„๋‹ ๊ฒƒ์ด๋‹ค.

 

์ด๋ก ์ƒ์œผ๋กœ Nutri Capture ํ”„๋กœ์ ํŠธ์— Cursor๋ฅผ ์“ฐ๋Š” ๊ฒŒ ๋‚˜๋น ๋ณด์ด์ง€๋Š” ์•Š๋Š”๋‹ค๋งŒ, ๊ทธ๋ž˜๋„ ๊ณต์‹๋ฌธ์„œ์˜ ์šฐ๋ ค(?)์— ๋”ฐ๋ผ์ฃผ๊ธฐ๋กœ ํ•œ๋‹ค. Cursor๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ž์› ํšจ์œจ ํ˜น์€ DB ์†๋„์— ๊ด€ํ•ด ๋” ๋น ๋ฅด๋‹ค๋Š” ํŒ๋‹จ์ด ์„ ๋‹ค๋ฉด, ๊ทธ๋ฆฌ๊ณ  Cursor ์‚ฌ์šฉ์— ๋Œ€ํ•œ ์ž ์žฌ์ ์ธ ์—๋Ÿฌ๋ฅผ ํ†ต์ œํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ ๋‹ค๋ฉด ๋‚˜์ค‘์— Cursor ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ• ์ง€๋„ ๋ชจ๋ฅด๊ฒ ๋‹ค.

 

#1-3 ๋‘๋ฒˆ์งธ ์‹œ๋„: ํ‰๋ฒ”ํ•œ SELECT๋ฌธ

์—ฌ๋А DAO์—์„œ๋‚˜ ๋ณผ ๋ฒ•ํ•œ ํ‰๋ฒ”ํ•œ SELECT๋ฌธ ํ•จ์ˆ˜๋กœ ๊ฐ€์ƒ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค. ๊ทธ ๊ตฌํ˜„์€ #2์— ์žˆ๋‹ค.

 

#2 ์ฝ”๋“œ

#2-1 DAO (MainDAO.kt)

...

@Dao
interface MainDAO {
    ...

    @Query("SELECT * FROM DayMealView")
    suspend fun getAllDayMeals(): List<DayMealView>

    @Query("""
    SELECT * FROM DayMealView 
    WHERE day_date <= :lastDate
      AND meal_time <= :lastTime 
      AND meal_id != :lastId
    LIMIT :limit
    """)
    suspend fun getNextDayMealsAfter(
        lastDate: LocalDate,
        lastTime: LocalTime,
        lastId: Long,
        limit: Int
    ): List<DayMealView>

    @Query("SELECT * FROM DayMealView WHERE meal_id = :mealId LIMIT 1")
    suspend fun getDayMeal(mealId: Long): DayMealView
}

๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ DayMeal์„ View์— ํ‘œ์‹œํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์ง€๋ง‰ DayMeal๋ณด๋‹ค ์‹œ๊ฐ„์ ์œผ๋กœ ์˜ค๋ž˜๋œ ๊ฒƒ์„ ๊ฐ€์ ธ์˜ค๊ฒŒ ํ•œ๋‹ค. ํ•ด๋‹น ํ•จ์ˆ˜์˜ ์ด๋ฆ„์„ getNextDayMealsAfter()๋กœ ๋ช…๋ช…ํ–ˆ๋Š”๋ฐ, ์ด์ „ ๊ฒŒ์‹œ๊ธ€์—์„œ ๋งŒ๋“  ํ•จ์ˆ˜ getAllMeals()์™€์˜ ์ด๋ฆ„ ํ†ต์ผ๊ฐ์„ ์œ„ํ•ด์„œ getAllMeals()๋ฅผ getAllDayMeals()๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

 

๋˜, getDayMeal() ํ•จ์ˆ˜๋„ ์ •์˜ํ•œ๋‹ค. ๋กœ๊ทธ ํ™•์ธ์„ ์œ„ํ•ด ํ•„์š”ํ•˜๋‹ค.

 

#2-2 Repository (MainRepository.kt)

...

class MainRepository(private val dao: MainDAO) {
    ...

    suspend fun getAllDayMeals(): List<DayMealView> {
        return dao.getAllDayMeals()
    }

    suspend fun getNextDayMealsAfter(lastDayMeal: DayMealView, limit: Int): List<DayMealView> {
        return dao.getNextDayMealsAfter(
            lastDayMeal.date, lastDayMeal.time, lastDayMeal.mealId, limit
        )
    }

    suspend fun getDayMeal(mealId: Long): DayMealView {
        return dao.getDayMeal(mealId)
    }
}

DAO์—์„œ๋Š” ๋ฌธ๋ฒ•์˜ ํ•œ๊ณ„๋กœ DayMeal์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ 3๊ฐœ์˜ ์ธ์ˆ˜๋กœ ๋‚˜๋ˆ  ๋ฐ›์•˜๋‹ค. Repository์—์„œ๋Š” DAO์™€ ๋˜‘๊ฐ™์ด ๋‹ต์Šตํ•˜์ง€ ์•Š๋Š”๋‹ค. DayMeal ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์„œ ์ •๋ณด๋ฅผ ๋ฝ‘์•„๋‚ธ๋‹ค. ๊ทธ๋ฆฌ๊ณ  DAO์— ์ž˜ ์ „๋‹ฌํ•ด์ค€๋‹ค. ๋˜, DAO์—์„œ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ–ˆ๋˜ ํ•จ์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๋Š” Repository์˜ ํ•จ์ˆ˜๋„ ์ด๋ฆ„์„ (getAllDayMeals()๋กœ) ๋ฐ”๊ฟ”์ค€๋‹ค.

 

DAO์˜ getDayMeal()๋ฅผ ์ฐธ์กฐํ•˜๋Š” Repository์˜ getDayMeal()๋„ ๋งŒ๋“ค์–ด์ค€๋‹ค.

 

#2-3 ViewModel (NutrientViewModel.kt)

...

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

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

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

    // (4) View๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
    ...

    // (5) DayMealView ์ž‘๋™ ํ™•์ธ์šฉ ๋กœ๊ทธ
    fun log() {
        viewModelScope.launch {
            Log.i("interfacer_han, getAllDayMeals()", repository.getAllDayMeals().toString())
            Log.i("interfacer_han, getNextDayMealsAfter()",
                repository.getNextDayMealsAfter(
                    repository.getDayMeal(6),
                    100
                ).toString()
            )
        }
    }
}

๋ทฐ๋ชจ๋ธ์˜ log() ํ•จ์ˆ˜๋ฅผ ์œ„์™€ ๊ฐ™์ด ๋ณ€๊ฒฝํ•œ๋‹ค. ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“  2๋ฒˆ์งธ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€์—์„œ๋Š”, (DayMealView์—์„œ) mealId๊ฐ€ 6์ธ ๋ ˆ์ฝ”๋“œ ์ดํ›„์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ์ค„ ๊ฒƒ์ด๋‹ค.

 

#3 ์š”์•ฝ

๊ฐ€์ƒํ…Œ์ด๋ธ” ์ฐธ์กฐ์— ํ•„์š”ํ•œ DAO ๋ฐ Repository ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ–ˆ๋‹ค. ๋‹ค์Œ ๊ฒŒ์‹œ๊ธ€์—์„  ํ”„๋ก ํŠธ์—์„œ DAO ๋ฐ Repository์˜ ํ•จ์ˆ˜๋ฅผ ์ฐธ์กฐํ•˜๊ฒŒ ๋งŒ๋“ค์–ด๋ณธ๋‹ค.

 

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

#4-1 ๋กœ๊ทธ ๋ฉ”์‹œ์ง€ (2๋ฒˆ์งธ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€)

[
DayMealView(
dayId=2, mealId=5, date=2024-11-12, time=07:48:08.852377, ...
),

DayMealView(
dayId=2, mealId=4, date=2024-11-12, time=07:48:08.591206, ...
),

DayMealView(
dayId=1, mealId=3, date=2024-11-11, time=07:48:07.773742, ...
)),

DayMealView(
dayId=1, mealId=2, date=2024-11-11, time=07:48:07.481481, ...
),

DayMealView(
dayId=1, mealId=1, date=2024-11-11, time=07:48:07.159289, ...
)
]

๋กœ๊ทธ ๋ฉ”์‹œ์ง€๊ฐ€ ์ž˜ ์ถœ๋ ฅ๋˜๋Š” ๋ชจ์Šต์ด๋‹ค. ์ฒซ๋ฒˆ์งธ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋Š” ์—ฌ๊ธฐ์— ์žˆ๋‹ค.

 

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

 

GitHub - Kanmanemone/nutri-capture-new

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

github.com

 

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

 

GitHub - Kanmanemone/nutri-capture-new

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

github.com