Android'de Veritabanı: SQLite ve Room Basit Anlatımla
Kısa cevap: Çoğu proje için Room kullanın — bu, dahili SQLite üzerine güvenli, tip korumalı bir katmandır; SQLite mini uygulamalar veya süper optimize edilmiş sorgular için uygundur. Aşağıda pratik bilgiler: Ne zaman hangisini seçmeli, Room'u hızlıca nasıl kurmalı ve tipik hatalardan nasıl kaçınmalı.
SQLite Nedir ve Ne Zaman Kullanılmalı
SQLite, Android'de tek bir dosyada saklanan (/data/data/…/databases/*.db) dahili bir ilişkisel veritabanıdır. Çevrimdışı veriler (notlar, önbellek, yerel ayarlar) için uygundur.
Avantajları:
- Hafif ve hızlıdır, SQL'i, işlemleri (transaction) ve indeksleri destekler.
- APK boyutuna minimal ek yük getirir.
Dezavantajları:
- Manuel SQL = daha fazla hata (yazım hataları, SQL enjeksiyonları, tip güvenliği eksikliği).
- Migrasyonları, thread yönetimini ve imleçlerin (cursor) kapatılmasını kendiniz yönetmeniz gerekir.
Sık yapılan hata: Veritabanına main thread üzerinden erişmek ve imleçleri kapatmamak. Bu, çökmelere ve bellek sızıntılarına yol açar.
SQLite'ı doğrudan ne zaman seçmeli:
- Süper optimize edilmiş, özel SQL operasyonlarına ihtiyaç varsa.
- Çok küçük bir prototip veya tek seferlik uygulama. Diğer tüm durumlarda — Room.
Room: Neden ve Nasıl Entegre Edilir (Adımlar)
Room, Jetpack'in bir parçasıdır: DAO/Entity/Database oluşturur, derleme zamanı kontrolleri sağlar, Coroutines, Flow, LiveData ve migrasyonları destekler.
- Bağımlılıkları ekleyin (Gradle Kotlin DSL örneği):
val roomVersion = "2.6.1"
implementation("androidx.room:room-runtime:$roomVersion")
implementation("androidx.room:room-ktx:$roomVersion")
kapt("androidx.room:room-compiler:$roomVersion") // veya KSP için ksp
- Entity — tablo modeli:
@Entity(tableName = "users")
data class User(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
@ColumnInfo(name = "full_name") val name: String
)
- DAO — işlem arayüzü:
@Dao
interface UserDao {
@Query("SELECT * FROM users")
suspend fun getAll(): List<User>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(user: User)
@Delete
suspend fun delete(user: User)
}
- Database — kök yapı:
@Database(entities = [User::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
Örnek oluşturma:
val db = Room.databaseBuilder(context, AppDatabase::class.java, "app-db").build()
Room, thread yönetimi (suspend / Flow / LiveData), migrasyonlar ve test süreçlerini kolaylaştırır.
UI için Flow veya LiveData kullanın — veriler değiştiğinde ekranı otomatik olarak güncellerler. exportSchema = true yapmak, migrasyon kontrolü için şema dosyalarını kaydetmenize yardımcı olur.
Pratik Örnek: TODO Uygulaması (Minimum Kod)
Entity:
@Entity
data class Task(
@PrimaryKey val id: String = UUID.randomUUID().toString(),
val title: String,
val isDone: Boolean = false,
@ColumnInfo(name = "created_at") val createdAt: Long = System.currentTimeMillis()
)
Flow içeren DAO:
@Dao
interface TaskDao {
@Query("SELECT * FROM Task WHERE isDone = 0 ORDER BY created_at DESC")
fun getPendingTasks(): Flow<List<Task>>
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(task: Task)
}
ViewModel:
class TaskViewModel(private val dao: TaskDao) : ViewModel() {
val pendingTasks = dao.getPendingTasks().asLiveData()
fun addTask(title: String) = viewModelScope.launch { dao.insert(Task(title = title)) }
}
Emülatörde Device File Explorer aracılığıyla veritabanını kontrol edin: dosya oluşacak ve veriler kaydedilecektir.
İki Satırda Karşılaştırma
- Doğrudan SQLite: Daha az bağımlılık, ancak daha fazla boilerplate kod ve risk.
- Room: +tip güvenliği, +daha az hata, +Coroutines/Flow desteği — projelerin %90'ı için tercih.
Sık Yapılan Hatalar
- Main thread üzerinden veritabanına erişim → suspend/Dispatchers.IO kullanın.
- Versiyon yükseltildiğinde migrasyon eklemeyi unutmak → uygulama çökebilir.
- Prod ortamında exportSchema = false kullanmak → şema kontrolünü kaybetmek.
- Room instance için yanlış scope kullanımı → singleton veya DI sağlayıcı tutun.
- Kötü indeksler → yavaş WHERE/ORDER BY sorguları.
SSS
- Küçük bir uygulama için Room gerekli mi?
- Basit bir prototip için SQLite ile yetinebilirsiniz, ancak Room küçük projelerde bile zaman kazandırır ve hataları azaltır.
- Room nasıl test edilir?
- Unit testler için Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java) kullanın.
- Prod ortamında migrasyonlarla ne yapılmalı?
- Migration nesneleri yazın ve test edin; fallbackToDestructiveMigration sadece geliştirme aşamasında veya bilinçli davranış için kullanılmalıdır.
- Kapt mı yoksa KSP mi?
- Yeni projelerde KSP önerilir (daha az derleme süresi), ancak KAPT hala desteklenmektedir.
Başarılar: Room ile başlayın, sık kullanılan sorgular için indeksler ekleyin ve Flow/LiveData kullanın — bu size stabilite ve kolay bir geliştirme deneyimi sunacaktır.