Android Room Database’e Giriş

Selamlar,

Android’de SQLite database kullanılmaktadır. Google bunun için Room adında bir kütüphane yayınladı. Bu kütüphane ile birlikte artık kolay bir şekilde local database kullanabiliyoruz. Bugün Room kütüphanesi nasıl kullanacağımızı anlatacağım.


Adım 1: Projeye Eklemek

build.gradle dosyamızda dependencies içerisinde aşağıdaki satırları ekleyelim

 def roomDatabase = "2.2.6"
 implementation "androidx.room:room-runtime:$roomDatabase"
 kapt "androidx.room:room-compiler:$roomDatabase"
 implementation "androidx.room:room-ktx:$roomDatabase"

Adım 2: Database Manager

DatabaseMagager adında bir abstract class oluşturalım. RoomDatabase sınıfından extend olsun. Database ile ilgili ayarları burada yapacağız. Hangi modelleri ekleyeceğiz, versiyonu ne olacak gibi.

Örnek kodu aşağıda paylaşıyorum

@Database(
    entities = [Notification::class, User::class],
    version = 31
)
abstract class DatabaseManager : RoomDatabase() {

    abstract fun notificationDao(): NotificationDao

    abstract fun userDao(): UserDao

    companion object {
        private const val DATABASE_NAME = "database1"

        @Volatile
        var INSTANCE: DatabaseManager? = null

        fun getDatabaseManager(context: Context): DatabaseManager {
            val tempInstance = INSTANCE
            if (tempInstance != null) {
                return tempInstance
            }

            synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    DatabaseManager::class.java,
                    DATABASE_NAME
                ).fallbackToDestructiveMigration().build()

                INSTANCE = instance
                return instance
            }
        }
    }
}

Class adının üzerinden @Database attonation’ı, data modellerini ve version isimlerini içermelidir. Yani Notification class’ı bir data class’dır.

Class’ın içerisindeki xDao denilen class’lar ise ilgili database’in yazma, silme, güncelleme gibi işlemleri yaptığımız class’dır.

Companion object içerisindekiler ise bir instance oluşturmak içindir.


Adım 3: Data Modelleri Oluşturmak

Yukarıdaki örnekten devam edelim. Mesela Notification adında bir model tanıtmıştık. Bu class’ın da içeriği aşağıdaki gibidir.

@Entity(tableName = TABLE_NAME)
data class Notification(
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,
    var title: String? = null,
    var description: String? = null
) {
    companion object {
        const val TABLE_NAME = "notification"
    }
}

Burada dikkat etmemiz gereken en önemli şey, sınıf adının hemen üzerine @Entity attonation’ı eklemek ve tableName vermek.

Bu class için id değeri girilmiştir. @PrimaryKey ile id değerinin tanımı yapılmıştır ve her yeni eklenen satıra göre otomatik olarak artacak şekilde autoGenerate = true olarak girilmiştir.

Eğer veritabanındaki adı ile kod içinde adını farklı yapmak istediğiniz zaman aşağıdaki gibi bir kullanım gerekmektedir.

 @ColumnInfo(name = "months") var months : MonthListModel? = null

Burada @ColumnInfo, veritabanındaki adıdır. Ama buna farklı bir variable ismi verebiliriz.


Adım 4: Dao Interface Oluşturmak

Yine burada da attonation kullanacağız interface’i tanımlamak için

Bir interface adının hemen üzerine @Dao yazarak o sınıfı, Room için tanınabilir hale getiriyoruz. Örnek kodumuzu paylaşalım

@Dao
interface NotificationDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertPost(posts: Notification)

    @Query("DELETE FROM ${Notification.TABLE_NAME}")
    fun deleteAllPosts()

    @Query("SELECT * FROM ${Notification.TABLE_NAME} WHERE ID = :postId")
    fun getPostById(postId: Int): Flow<Notification>


    @Query("SELECT * FROM ${Notification.TABLE_NAME}")
    fun getAllPosts(): Flow<List<Notification>>
}

İçeride tanımlanan methodlar @Insert ve @Query, tabloya ekleme, silme, güncelleme ve olarak almak için kullanılmıştır.

@Insert(onConflict = OnConflictStrategy.REPLACE) herhangi bir çakışma olması durumunda üzerine yazmak için kullanılmıştır.

NOT: Room kütüphanesi, sonuçları size Flow türünden verebilmektedir. Örneğimizde sonuçları Flow ile alıp, ViewModel sınıfımızda bir scope içerisinde OI thread olarak okuyabiliriz. Eğer Flow yazmazsanız normal olarak da değerleri alabilirsiniz.


Adım 5: Kullanım

Şimdi nasıl ekleme yapacağımıza bakalım. Ama önce hemen bir not daha

NOT: Room database sadece IO thread’de çalışır. Main thread’de çalıştırmayın hata alırsınız.

DatabaseManager.getDatabaseManager(context).userDao().insertPosts(user)

kodu ile tabloya ekleme yapabilir,

getDatabaseManager(context).userDao().getAllPosts()

kodu ile de verileri çekebilirsiniz.

Eğer coroutines kullanıyorsanız örnek kullanımı şu şekilde yapabilirsiniz

NOT: Room, çalışabilmek için context istemektedir. Siz burada applicationContext verebilirsiniz. Eğer dagger 2 kullanıyorsanız zaten bir applicationContext instance vardır.

ViewModel

fun getUser() = viewModelScope.launch {
        val response = userRepository.getUser(context)
        response?.let {
            _user.value = it
        }
    }

_user, bir LiveData’dır. context ise (her ne kadar doğru bulmasam da) viewModel içerisindeki applicationContext’dir.

Repository

suspend fun getUser(context: Context): User? = withContext(Dispatchers.IO) {
         localService.getDatabaseManager(context).userDao().getAllPosts()
    }

Sonuç

Bu örnek MVVM ve Coroutines ağırlıklı bir örnek oldu. Başka mimarilerde eklemekte zorluk yaşarsanız aşağıya yorum olarak yazarsanız, yardımcı olmaya çalışırım.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir