이번에 소개할 기술은 Room 입니다.
AAC의 하나인 Room은 기존에 SQLite를 좀 더 쉽게 쓸 수 있게 만든거라고 생각하시면 됩니다.
주요 구성 요소
Room에는 세 가지 주요 구성요소가 있습니다.
Google Document에 있는 내용입니다.
Room에서 필요한 3가지 요소를 나타낸 것 입니다.
DataBase, Data Entity, DAO가 있습니다.
간단하게 알아보겠습니다.
@Database(
entities = [LikeCharacterVo::class, RecentSearchVO::class],
version = 2,
exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
abstract fun likeCharacterDao(): LikeCharacterDao
abstract fun recentSearchDao(): RecentSearchDao
}
entities는 간단히 말하면 Table의 역할을 합니다.
version은 변경사항이 생길 때 하나씩 올려주면됩니다. 올리지 않고 빌드를 한다면 에러를 마주칠 것입니다.
exportSchema는 Room의 스키마를 폴더로 내보내도록 지시할 수 있습니다.
@Entity(tableName = "like_table", indices = [Index(value = ["nickName"], unique = true)])
data class LikeCharacterVo(
@PrimaryKey(autoGenerate = true)
val id : Long = 0,
val nickName: String,
val imgUrl: String,
val level : String
)
이번에 메이플스토리 관련 앱을 만들면서 쓰던 캐릭터 즐겨찾기의 엔티티 구조입니다.
우선 Table Name을 정해주고 indices 속성에 nickName필드를 unique 고유 속성으로 만든 엔티티입니다. 만일 닉네임이 같은 경우 추후 Insert를 하게 되면 에러가 난다거나 덮어쓰기를 한다거나 개발자가 정해준 방식을 취할 것 입니다. 하지만 제가 만든 앱은 메이플에서 닉네임을 생성할 때 중복이 방지되므로 저는 덮어쓰기 방식을 채택했습니다. 나머지 필드들은 자기가 넣어주고 싶은 필드들을 넣어주시면 됩니다.
@PrimaryKey(autoGenerate = true)
val id : Long = 0
이 부분은 보통 index로 많이 쓰는 부분입니다. 자동으로 카운트가 됩니다.
@Dao
interface LikeCharacterDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertLickCharacter(likeCharacterVo: LikeCharacterVo)
@Query("SELECT * FROM like_table")
fun getAllLikeCharacter(): LiveData<List<LikeCharacterVo>>
@Query("DELETE FROM like_table WHERE nickName = :nickName")
suspend fun deleteData(nickName: String)
@Query("SELECT * FROM like_table WHERE nickName = :name")
fun getCharacterByName(name : String): LikeCharacterVo?
}
즐겨찾기 Dao입니다.
Dao는 테이블에 접근하려고 하는 object? 정도 라고 생각하시면 편할 것 같습니다.
사실 Update도 만들어야 하지만 insert를 할 때
onConflict = OnConflictStrategy.REPLACE
Insert에 옵션을 주면 해당 옵션은 중복값이 있을 때 교체를 한다는 뜻입니다.
그래서 저는 따로 Update는 만들지 않았습니다.
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Singleton
@Provides
fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
return Room.databaseBuilder(
context,
AppDatabase::class.java,
"LikeCharacterDatabase"
).build()
}
@Provides
fun provideLikeCharacterDao(database: AppDatabase): LikeCharacterDao {
return database.likeCharacterDao()
}
}
DB객체는 싱글톤으로 구현하는 걸 추천하고 있습니다. 공식문서를 참조해주세요.
@HiltViewModel
class LikeCharacterViewModel @Inject constructor(private val likeCharacterRepository: LikeCharacterRepository) : ViewModel() {
private val _characterData = MutableLiveData<List<LikeCharacterVo>>()
val characterData: LiveData<List<LikeCharacterVo>> get() = _characterData
fun insertLikeCharacter(name: String, imgUrl: String, level : String) {
viewModelScope.launch {
try {
val likeCharacterVo = LikeCharacterVo(nickName = name, imgUrl = imgUrl, level = level)
likeCharacterRepository.insertCharacter(likeCharacterVo)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
fun deleteLikeCharacter(name: String) {
viewModelScope.launch {
try {
likeCharacterRepository.deleteUser(name)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
fun getAllList() {
likeCharacterRepository.getAllCharacterList().observeForever {
_characterData.value = it
}
}
suspend fun isExistCharacter(name: String): Boolean {
return withContext(Dispatchers.IO) {
likeCharacterRepository.isExistCharacter(name)
}
}
}
그리고 viewModel로 만들어서 원하는 곳에서 가져다 쓰면 됩니다.
해당 링크를 통해 Room에 대해 더 자세히 알아보시면 좋을 것 같습니다.