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

Nutri Capture - Room ๊ฐ€์ƒ ํ…Œ์ด๋ธ”

interfacer_han 2024. 11. 10. 16:18

#1 ๊ฐœ์š”

#1-1 ์ฑ„ํŒ… UI ๊ตฌํ˜„์„ ์œ„ํ•œ ์ฒซ ๊ฑธ์Œ

'์ฑ„ํŒ… UI'์—์„œ ํ‘œ์‹œํ•  ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜์˜ ๋ ˆ์ฝ”๋“œ๋กœ์„œ ๊ฐ€์ง€๋Š” ๊ฐ€์ƒ ํ…Œ์ด๋ธ”์„ ์„ ์–ธํ•œ๋‹ค.

 

#1-2 ๊ฐ€์ƒ ํ…Œ์ด๋ธ” (SQLite)

SELECT day_table.day_id AS day_id,
       meal_table.meal_id AS meal_id,
       day_table.day_date AS day_date, 
       meal_table.meal_time AS meal_time,
       meal_table.meal_name AS meal_name,
       /* NutritionInfo์˜ Column ์‹œ์ž‘ */
       meal_table.overeating_excess AS overeating_excess,
       meal_table.refined_sugar_excess AS refined_sugar_excess,
       meal_table.refined_grain_excess AS refined_grain_excess,
       meal_table.flour_excess AS flour_excess,
       meal_table.fiber_quality AS fiber_quality,
       meal_table.protein_quality AS protein_quality,
       meal_table.sodium_excess AS sodium_excess
       /* NutritionInfo์˜ Column ๋ */
FROM day_table
INNER JOIN meal_table ON meal_table.day_id = day_table.day_id
ORDER BY day_table.day_date DESC,
         meal_table.meal_time DESC,
         meal_table.meal_id DESC

์ฑ„ํŒ… UI๋Š” ๊ฐ€์žฅ ์ตœ๊ทผ์˜ ์‹๋‹จ๋ถ€ํ„ฐ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ๋ณด์—ฌ์ค€๋‹ค. ๋”ฐ๋ผ์„œ, Query๋ฌธ์— ์žˆ๋Š” 3๊ฐœ์˜ ์ •๋ ฌ ๊ธฐ์ค€์„ ์ „๋ถ€ ๋‚ด๋ฆผ์ฐจ์ˆœ(DESC)์œผ๋กœ ๋‘์—ˆ๋‹ค.

 

#2 ์ฝ”๋“œ - ๊ฐ€์ƒ ํ…Œ์ด๋ธ”

#2-1 ๊ฐ€์ƒ ํ…Œ์ด๋ธ” (Room)

// package com.example.nutri_capture_new.db

import androidx.room.ColumnInfo
import androidx.room.DatabaseView
import androidx.room.Embedded
import java.time.LocalDate
import java.time.LocalTime

/*
Day ํ…Œ์ด๋ธ”์˜ dayId์™€ Day์˜ ์ž์‹์ธ Meal ํ…Œ์ด๋ธ”์˜ dayId๊ฐ€ ๊ฐ™์€(==) ์กฐ๊ฑด์œผ๋กœ INNER JOINํ•˜๋˜,
์ฒซ์งธ๋กœ๋Š” Day.date์— ๋Œ€ํ•ด ๋‚ด๋ฆผ์ฐจ์ˆœ,
๋‘˜์งธ๋กœ๋Š” Meal.time์— ๋Œ€ํ•ด ๋‚ด๋ฆผ์ฐจ์ˆœ,
์…‹์งธ๋กœ๋Š” Meal.mealId์— ๋Œ€ํ•ด ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ
*/
@DatabaseView("""
    SELECT day_table.day_id AS day_id,
           meal_table.meal_id AS meal_id,
           day_table.day_date AS day_date, 
           meal_table.meal_time AS meal_time,
           meal_table.meal_name AS meal_name,
           /* NutritionInfo์˜ Column ์‹œ์ž‘ */
           meal_table.overeating_excess AS overeating_excess,
           meal_table.refined_sugar_excess AS refined_sugar_excess,
           meal_table.refined_grain_excess AS refined_grain_excess,
           meal_table.flour_excess AS flour_excess,
           meal_table.fiber_quality AS fiber_quality,
           meal_table.protein_quality AS protein_quality,
           meal_table.sodium_excess AS sodium_excess
           /* NutritionInfo์˜ Column ๋ */
    FROM day_table
    INNER JOIN meal_table ON meal_table.day_id = day_table.day_id
    ORDER BY day_table.day_date DESC,
             meal_table.meal_time DESC,
             meal_table.meal_id DESC
""")
data class DayMealView(
    @ColumnInfo(name = "day_id")
    val dayId: Long,

    @ColumnInfo(name = "meal_id")
    val mealId: Long,

    @ColumnInfo(name = "day_date")
    var date: LocalDate,

    @ColumnInfo(name = "meal_time")
    var time: LocalTime,

    @ColumnInfo(name = "meal_name")
    var name: String,

    @Embedded
    val nutritionInfo: NutritionInfo
)

"db" ํŒจํ‚ค์ง€์— ๋‘์—ˆ๋‹ค.

 

#2-2 MainDatabase.kt

// package com.example.nutri_capture_new.db

...

@Database(
    entities = ...,
    views = [DayMealView::class],
    version = ...
)
...
abstract class MainDatabase : RoomDatabase() {

    ...
}

๋ฐฉ๊ธˆ ์„ ์–ธํ•œ ๊ฐ€์ƒ ํ…Œ์ด๋ธ”์„ Room์ด ์ธ์‹ํ•  ์ˆ˜ ์žˆ๊ฒŒ views ํ”„๋กœํผํ‹ฐ์— ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

 

#3 ์ฝ”๋“œ - ๊ฐ€์ƒ ํ…Œ์ด๋ธ”์˜ ๋ ˆ์ฝ”๋“œ ํ™•์ธ

#3-1 DAO (MainDAO.kt)

...

@Dao
interface MainDAO {
    ...

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

 

#3-2 Repository (MainRepository.kt)

...

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

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

 

#3-3 ViewModel (NutrientViewModel.kt)

// package com.example.nutri_capture_new.nutrient

...
import android.util.Log

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", repository.getAllMeals().toString())
        }
    }
}

Repository์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ViewModel์— Log๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ViewModel์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ View์—์„œ ํ˜ธ์ถœ(#3-4 ์ฐธ์กฐ)ํ•  ๊ฒƒ์ด๋‹ค.

 

#3-4 View (NutrientScreen.kt)

...

@Composable
fun NutrientScreen(
    ...
) {
    LaunchedEffect(key1 = true) {
        // DayMealView ์ž‘๋™ ํ™•์ธ์šฉ ๋กœ๊ทธ
        viewModel.log()

        ...
    }

    ...
}

 

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

#4-1 ์Šคํฌ๋ฆฐ์ƒท

๋กœ๊ทธ ๋ฉ”์‹œ์ง€๋Š” ์•ฑ ์‹œ์ž‘๊ณผ ๋™์‹œ์— ์ถœ๋ ฅ๋˜๋ฏ€๋กœ, ์œ„์™€ ๊ฐ™์€ ์ƒํƒœ๋ฅผ ๋งŒ๋“ค๊ณ  ์•ฑ์„ ์žฌ์‹œ์ž‘ํ•˜๋ฉด 11์ผ์ธ Meal 3๊ฐœใ†12์ผ์ธ Meal 2๊ฐœใ†13์ผ์ธ Meal 1๊ฐœใ†14์ผ์ธ Meal 4๊ฐœ๊ฐ€ ์ถœ๋ ฅ๋  ๊ฒƒ์ด๋‹ค (#4-2 ์ฐธ์กฐ).

 

#4-2 ๋กœ๊ทธ ๋ฉ”์‹œ์ง€

๋”๋ณด๊ธฐ
[
DayMealView(
dayId=4, mealId=10, date=2024-11-14, time=07:48:11.077044, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 )
),

DayMealView(
dayId=4, mealId=9, date=2024-11-14, time=07:48:10.831407, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 )
),

DayMealView(
dayId=4, mealId=8, date=2024-11-14, time=07:48:10.634030, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 )
),

DayMealView(
dayId=4, mealId=7, date=2024-11-14, time=07:48:10.453062, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 )
),

DayMealView(
dayId=3, mealId=6, date=2024-11-13, time=07:48:09.646245, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 )
),

DayMealView(
dayId=2, mealId=5, date=2024-11-12, time=07:48:08.852377, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 ) ),

DayMealView(
dayId=2, mealId=4, date=2024-11-12, time=07:48:08.591206, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 )
),

DayMealView(
dayId=1, mealId=3, date=2024-11-11, time=07:48:07.773742, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 )
),

DayMealView(
dayId=1, mealId=2, date=2024-11-11, time=07:48:07.481481, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 )
),

DayMealView(
dayId=1, mealId=1, date=2024-11-11, time=07:48:07.159289, name=์ž๋™ ์ƒ์„ฑ๋œ Meal, nutritionInfo=NutritionInfo( overeatingExcess=0, refinedSugarExcess=0, refinedGrainExcess=0, flourExcess=0, fiberQuality=0, proteinQuality=0, sodiumExcess=0 )
)
]

๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ๋œ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ž˜ ์ถœ๋ ฅ๋œ๋‹ค.

 

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

 

GitHub - Kanmanemone/nutri-capture-new

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

github.com

 

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

 

GitHub - Kanmanemone/nutri-capture-new

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

github.com