Notice
Recent Posts
Recent Comments
Link
ยซ   2025/08   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Tags
more
Archives
Today
Total
๊ด€๋ฆฌ ๋ฉ”๋‰ด

๐ŸŒฑ dreaming DiNO

[Kotlin] Room db Migration ๋ฐฉ๋ฒ• + Gson ์ด์šฉํ•ด ๋‹ค์–‘ํ•œ ํƒ€์ž… ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๊ธฐ ๋ณธ๋ฌธ

Android/Android Studio

[Kotlin] Room db Migration ๋ฐฉ๋ฒ• + Gson ์ด์šฉํ•ด ๋‹ค์–‘ํ•œ ํƒ€์ž… ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๊ธฐ

MK_____ 2022. 5. 12. 17:23
ํ…Œ์ด๋ธ”์— ์‚ฌ์šฉ์ž๊ฐ€ ์ถ”๊ฐ€ํ•œ ์‚ฌ์ง„์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด image column ์ด ์ถ”๊ฐ€๋  ํ•„์š”์„ฑ ์ƒ๊น€

1.  Room์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋•Œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ primitive type๊ณผ ๊ทธ wrapping ํƒ€์ž…๋งŒ ์ง€์›

ํ•˜์ง€๋งŒ ๋‚˜๋Š” image uri์˜ path๋ฅผ List๋กœ ์ €์žฅ์„ ํ•˜๋ ค๊ณ  ํ•œ๋‹ค

 

 

2. Gson ์ด์šฉํ•˜์—ฌ TypeConverter ํด๋ž˜์Šค ์ƒ์„ฑ

TypeConverter

Room์— primitive type์ด ์•„๋‹Œ ๋‹ค๋ฅธ ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด์„  Room์—์„œ ์ œ๊ณตํ•˜๋Š” TypeConverter ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

class Converters {
    @TypeConverter
    fun fromTimestamp(value: Long?): Date? {
        return value?.let { Date(it) }
    }
    
    @TypeConverter
    fun dateToTimestamp(date: Date?): Long? {
        return date?.time?.toLong()
    }
}

์œ„ ์†Œ์Šค๋ฅผ ์ฐธ๊ณ ๋กœ ํ•ด์„œ ๋งŒ๋“ค์—ˆ๋‹ค.

package com.example.memolog.repository

import android.util.Log
import androidx.room.ProvidedTypeConverter
import com.google.gson.Gson

@ProvidedTypeConverter
class StringListTypeConverter(private val gson: Gson) {

    @androidx.room.TypeConverter
    fun listToJson(value: List<String>?): String? {
        return value?.let{ gson.toJson(value) }
    }

    @androidx.room.TypeConverter
    fun jsonToList(value: String?): List<String> {
        return if(value?.isEmpty() == true){ // "" ๊ณต๋ฐฑ๊ฐ’
            Log.d("MemoDebug", "value==$value==")
            emptyList()
        }else{
            gson.fromJson(value, Array<String>::class.java).toList()
        }
    }

}

** isEmpty() ์™€ null ์˜ ์ฐจ์ด

Type๋ณ€ํ™˜ ํ• ๋•Œ ์ž๊พธ null์ด ๋“ค์–ด์™€์„œ ์–ด๋–ป๊ฒŒ Gson์ด ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜ํ•ด์•ผ ํ• ์ง€ ๋ชฐ๋ผ์„œ null ์„ ์ฒดํฌํ–ˆ์–ด์•ผ ํ–ˆ๋‹ค.

https://coding-mia.tistory.com/139

 

[Kotlin] Null vs Empty vs Blank

์ œ๊ฐ€ empty์™€ blank๊ฐ€ ๋งค์ผ ํ—ท๊ฐˆ๋ ค์„œ ํ™•์‹คํ•˜๊ฒŒ ์งš๊ณ  ๋„˜์–ด๊ฐ€๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. String Validation ํ™•์ธ ์ค‘, ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” Null, Empty, Blank์˜ ์ฐจ์ด๋ฅผ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์ฝ”๋“œ๋“ค์€ group: org.apache.commons..

coding-mia.tistory.com

 

 

3. AppDatabase.kt ๋ฒ„์ „ ์˜ฌ๋ฆฌ๊ธฐ, ๋งŒ๋“  TypeConverter ์ถ”๊ฐ€

@Database(
    entities = [Memo::class],
    version = 2
)
@TypeConverters(
    value = [StringListTypeConverter::class]
)
abstract class AppDatabase : RoomDatabase() {
    abstract fun memoDao(): MemoDao
}

 

4. Database ์ƒ์„ฑํ•ด์ฃผ๋Š” ๊ณณ ๊ฐ€์„œ column ์ถ”๊ฐ€, migration ์ •์˜ ๋ฐ ์ถ”๊ฐ€

class GlobalApplication: Application() {
    companion object{
        lateinit var appInstance: GlobalApplication
            private set

        lateinit var databaseInstance: AppDatabase
            private set

        fun provideGson(): Gson {
            return Gson()
        }

        private val MIGRATION_1_2 = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE 'memo' ADD COLUMN 'image' TEXT NOT NULL DEFAULT ''")
            }
        }
    }

    override fun onCreate() {
        super.onCreate()
        appInstance = this

        databaseInstance = Room.databaseBuilder(
            appInstance.applicationContext,
            AppDatabase::class.java, "exampleApp.db"
        )
            //.fallbackToDestructiveMigration() // ์ด์ „์— ์ƒ์„ฑํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ญ์ œํ•œ ํ›„ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ƒ์„ฑ
            .allowMainThreadQueries()
            .addTypeConverter(StringListTypeConverter(provideGson()))
            .addMigrations(MIGRATION_1_2)
            .build()
    }
}

 

์›๋ž˜ ๋‚ด ์˜๋„๋Š” image column ์ž์ฒด๋ฅผ nullable ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ์—ˆ๋Š”๋ฐ, ๊ทธ ๋ฐฉ๋ฒ•์„ ์•„์ง ์ฐพ์ง€ ๋ชปํ•ด ์ผ๋‹จ NOT NULL๋กœ DEFAULT ๊ฐ’์„ '' ๊ณต๋ฐฑ์„ ๋„ฃ์–ด์ฃผ์—ˆ๋‹ค. 

database.execSQL("ALTER TABLE 'memo' ADD COLUMN 'image' TEXT NOT NULL DEFAULT ''")

 

<Migration ์ ์šฉ ํ›„>

๊ธฐ์กด memo data ์—์„œ image ์ปฌ๋Ÿผ์ด ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.

DEFAULT ๋กœ '' ๊ณต๋ฐฑ์„ ๋„ฃ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ฌด ๊ฐ’์ด ์—†๋‹ค.

 

์ƒˆ๋กœ์šด data๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋”๋‹ˆ [""] ์ด ์ถ”๊ฐ€๋˜์—ˆ๋‹ค. 

 

 

memo๋ฅผ insert ํ•˜๋Š” ๊ณณ์„ ์ด๋ ‡๊ฒŒ ์ถ”๊ฐ€ ํ•ด์คฌ๋‹ค. ๊ทธ๋ž˜์„œ [""] ๊ณต๋ฐฑ ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ถ”๊ฐ€ ๋˜์—ˆ๋‹ค.


์ถœ์ฒ˜: 
https://leveloper.tistory.com/215 [๊พธ์ค€ํ•˜๊ฒŒ]

 


๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ๋ณ€ํ™” ์—๋Ÿฌ ๋ฌธ์ œํ•ด๊ฒฐ

https://android-dev.tistory.com/49