Android’e ait bir oda*: Room

Merve Karaman
DigiGeek
Published in
3 min readJan 27, 2021

Virginia Woolf meşhur kitabında* kişinin kendini gerçekleştirmesi için kendine ait bir odaya ya da alana ihtiyacını vurgular. Peki bizim için Android Room’da vurgulanması gerek en önemli şey nedir? Tek bir cümle ile belirtecek olursam Room client tarafında veri tutmamızı sağlayan ve bunu bizim için çok kolaylaştıran bir jetpack componenti. Daha fazla detay içinse, sizi yazının geri kalanını okumaya davet ediyorum :)

Photo by Philipp Berndt on Unsplash

Android Jetpack component’larından biri olan Room’u uzun süredir duyuyordum hatta arkadaşımın örnek proje sunumunda da dinlemiştim, ama Udacity eğitiminde denk gelmesem gerçekten bu kadar kolay ve kullanışlı olacağını tahmin edemezdim. Bu sebeple de üzerine yazmak istedim.

Room, uygulamanız içinde client tarafında veri saklamamızı sağlayan güçlü bir veritabanı kütüphanesidir. SQLite’ın tüm gücünden yararlanmamızı sağlarken, kullanım kolaylığı ile veriye erişmek hiç bu kadar kolay olmamıştı. Örneklere geçtikçe ne demek istediğim daha da somutlaşacak.

Öncelikle projenizde Room kullanmak için app build.gradle’a aşağıdaki dependencyleri eklemelisiniz

dependencies {
def room_version = "2.2.6"

implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"

// optional - Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"

// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
}

Room’da 3 temel bileşen vardır. İlki Entity’dir. Entity’leri kotlindeki data class’larla ifade edebiliriz. Server-side veritabanlarındaki tablolara karşılık gelir. Kotlinde oluşturduğumuz data class’ın başına @Entity annotationını kullanarak onu tabloya çevirebiliriz. Karşılık gelecek tablo ismini de aşağıdaki örnekteki gibi yanına parantez içinde belirtiriz. Tablonun Primary Key’ini de yine “@PrimaryKey” annotationı olarak belirtilir. Bu zorunlu bir alandır. Eğer primaryKey kimlik numarası gibi unique bir değer değilse yanına parantez içinde @PrimaryKey(autoGenerate = true) yazarak, Room’un onu otomatik kendi oluşturmasını ve arttırmasını sağlarız.

@Entity(tableName = "customer_orders_table")
data class CustomerOrder(
@PrimaryKey(autoGenerate = true)
var orderId: Long = 0L,

@ColumnInfo(name = "create_time_milli")
val createTimeMilli: Long = System.currentTimeMillis(),

@ColumnInfo(name = "quantity")
var quantity: Int = 0
@ColumnInfo(name = "price")
var price: Double = 0D
)

Room’un 2. önemli bileşeni de DAO(Data Access Object). Room kullandığınızda, DAO içinde gerekli annotationlarla fonksiyonları tanımlayarak ve onları kullanarak veritabanına sorgu yapabilirsiniz. Bu fonksiyonları SQL querylere dönüştürecek kodu Room kendi oluşturur. DAO’yu veritabanına erişmek için custom bir interface olarak düşünebiliriz.

Room DAO annotionları aşağıdaki gibidir. Insert/Delete/Update için özel bir SQL sorgusu yazmamıza gerek yok. Query içinse de SQLite’ın desteklediği her türlü sorguyu yazabiliriz.

@Insert
@Delete
@Update
@Query

DAO define edildiğinde, Room bizim için DB Querylerini ve fonksiyonları mapleyecek tüm kotlin kodunu kendi oluşturur. Bonus bir özellik de querylerimiz de bir syntax hatası varsa Android Studio compiler’ı bunları kontrol edip bizi uyarır.

@Dao
interface CustomerOrderDatabaseDao {

@Insert
suspend fun insert(order: CustomerOrder)

@Update
suspend fun update(order: CustomerOrder)

@Query("SELECT * from customer_orders_table WHERE orderId = :key")
suspend fun get(key: Long): CustomerOrder?

@Query("DELETE FROM customer_orders_table")
suspend fun clear()

@Query("SELECT * FROM customer_orders_table ORDER BY orderId DESC")
suspend fun getAllOrders(): LiveData<List<ORDER>>

@Query("SELECT * FROM customer_orders_table ORDER BY orderId DESC LIMIT 1")
suspend fun getOrder(): ORDER?
}

Room’un en önemli özelliklerinden biri Livedata return edebilmesi. Böylece DBde bir güncelleme olduğunda Room da Livedatan’ın güncellendiğinden emin oluyor. Yukarıdaki örnekteki getAllOrders ı bir kere çağırıp, observer a bağladığımızda, bir güncelleme olduğunda UI’da otomatik güncellenecek. Bu özellik sayesinde tekrar tekrar listeyi query etmemiz gerekmeyecek. Bu bize hem zaman, hem de kod kompleksitesinden tasarruf sağlayacaktır.

3. ve son bileşen Database Yaratımı. @Databaseannotationı ile veritabanı sınıfını yaratırız. Burda önemli olan Entity’leri belirtmek. Bizim örneğimizde 1 tane entityi ve DAO var, ama siz ihtiyacınıza göre sayıyı arttırabilirsiniz. Version ile veritabanı versiyonunuzu belirtirken exportSchema değeri ile de veritabanı schemasının folder export edilebilir olma özelliğini set edersiniz.

@Database(entities = [CustomerOrder::class], version = 1, exportSchema = false)
abstract class CustomerOrderDatabase : RoomDatabase() {

abstract val customerOrderDatabaseDao: CustomerOrderDatabaseDao

companion object {

@Volatile
private var INSTANCE: CustomerOrderDatabase? = null

fun getInstance(context: Context): CustomerOrderDatabase {
synchronized(this) {
var instance = INSTANCE

if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
CustomerOrderDatabase::class.java,
"order_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}

Yukarıdaki örnekte, companion object ile veritabanını singleton yapıyoruz. Böylece bir kez oluşturulup, bir sonraki çağrımlarda varolan DB objesi kullanılıyor. Ayrıca DB ye erişimlerde erişim açma/kapama konusunda sıkıntı oluşmuyor. @Volatile annotationını da cachelenmeyi engellemek için kullanıyoruz. Synchronized olması ise DBde tek thread işlem yapabilsin diye. Daha kompleks appler de önemli bir ayrıntı.

Android Developer Advocat Florina Muntenescu’nin sözleriyle özetleyecek olursak Room kullanımı çok kolay, hata yapmayı minimuma indirgeyen bir veritabanı kütüphanesi. Manuel DB yaratmak için ekstra kod yazmaya ihtiyaç yok, az boilerplate kodu sayesinde de “daha az kod daha az hata” diyebiliriz. Hiç mi dezavantajı yok derseniz de, şu an için encrypted veritabanı desteği yok.

--

--