Verilerin veritabanına kaydedilmesi, iletişim bilgileri gibi tekrarlanan veya yapılandırılmış veriler için idealdir. Bu sayfada SQL veritabanlarına genel olarak aşina olduğunuz varsayılır ve Android'de SQLite veritabanlarını kullanmaya başlamanıza yardımcı olur. Android'de veritabanı kullanmak için ihtiyacınız olan API'ler android.database.sqlite
paketinde mevcuttur.
Dikkat: Bu API'ler güçlü olsalar da oldukça düşük seviyelidir ve çok zaman ve çaba gerektirirler:
- Ham SQL sorgularının derleme sırasında doğrulanması gerekmez. Veri grafiğiniz değiştikçe, etkilenen SQL sorgularını manuel olarak güncellemeniz gerekir. Bu işlem zaman alıcı ve hataya açık olabilir.
- SQL sorguları ve veri nesneleri arasında dönüşüm yapmak için çok sayıda standart kod kullanmanız gerekir.
Bu nedenlerle, uygulamanızın SQLite veritabanlarındaki bilgilere erişmek için bir soyutlama katmanı olarak Oda Kalıcılığı Kitaplığı'nı kullanmanızı önemle tavsiye ederiz.
Şema ve sözleşme tanımlayın
SQL veritabanlarının ana ilkelerinden biri, veritabanının nasıl düzenlendiğinin resmi bir beyanı olan şemadır. Şema, veritabanınızı oluşturmak için kullandığınız SQL ifadelerine yansıtılır. Şemanızın düzenini sistematik ve kendi kendini belgeleyen bir şekilde açıkça belirten ve sözleşme sınıfı olarak bilinen bir tamamlayıcı sınıf oluşturmak işinize yarayabilir.
Sözleşme sınıfı; URI'ler, tablolar ve sütunların adlarını tanımlayan sabit değerler için bir kapsayıcıdır. Sözleşme sınıfı, aynı paketteki diğer tüm sınıflarda aynı sabitleri kullanmanıza olanak tanır. Bu da sütun adını tek bir yerde değiştirmenize ve kodunuza yayılmasını sağlamanıza olanak tanır.
Bir sözleşme sınıfını düzenlemenin iyi bir yolu, tüm veritabanınız için genel olan tanımları sınıfın kök düzeyine yerleştirmektir. Sonra her tablo için bir iç sınıf oluşturun. Her iç sınıf, karşılık gelen tablonun sütunlarını numaralandırır.
Not: BaseColumns
arayüzünü uygulayarak iç sınıfınız, CursorAdapter
gibi bazı Android sınıflarının sahip olmasını beklediği birincil anahtar alanını _ID
adlı birincil anahtar alanını devralabilir. Zorunlu değildir ancak veritabanınızın Android çerçevesiyle uyumlu bir şekilde çalışmasına yardımcı olabilir.
Örneğin, aşağıdaki sözleşmede bir RSS özet akışını temsil eden tek bir tablo için tablo adı ve sütun adları tanımlanır:
Kotlin
object FeedReaderContract { // Table contents are grouped together in an anonymous object. object FeedEntry : BaseColumns { const val TABLE_NAME = "entry" const val COLUMN_NAME_TITLE = "title" const val COLUMN_NAME_SUBTITLE = "subtitle" } }
Java
public final class FeedReaderContract { // To prevent someone from accidentally instantiating the contract class, // make the constructor private. private FeedReaderContract() {} /* Inner class that defines the table contents */ public static class FeedEntry implements BaseColumns { public static final String TABLE_NAME = "entry"; public static final String COLUMN_NAME_TITLE = "title"; public static final String COLUMN_NAME_SUBTITLE = "subtitle"; } }
SQL yardımcısı kullanarak veritabanı oluşturma
Veritabanınızın nasıl göründüğünü tanımladıktan sonra veritabanını ve tabloları oluşturup bunları koruyan yöntemler uygulamanız gerekir. Tablo oluşturan ve silen bazı tipik ifadeler şunlardır:
Kotlin
private const val SQL_CREATE_ENTRIES = "CREATE TABLE ${FeedEntry.TABLE_NAME} (" + "${BaseColumns._ID} INTEGER PRIMARY KEY," + "${FeedEntry.COLUMN_NAME_TITLE} TEXT," + "${FeedEntry.COLUMN_NAME_SUBTITLE} TEXT)" private const val SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS ${FeedEntry.TABLE_NAME}"
Java
private static final String SQL_CREATE_ENTRIES = "CREATE TABLE " + FeedEntry.TABLE_NAME + " (" + FeedEntry._ID + " INTEGER PRIMARY KEY," + FeedEntry.COLUMN_NAME_TITLE + " TEXT," + FeedEntry.COLUMN_NAME_SUBTITLE + " TEXT)"; private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
Cihazın dahili depolama alanına kaydettiğiniz dosyalar gibi, Android de veritabanınızı uygulamanızın özel klasöründe depolar. Varsayılan olarak diğer uygulamalar veya kullanıcı bu alana erişemediğinden verileriniz güvendedir.
SQLiteOpenHelper
sınıfı, veritabanınızı yönetmeniz için faydalı bir API grubu içerir.
Veritabanınıza referans almak için bu sınıfı kullandığınızda, sistem yalnızca ihtiyaç duyulduğunda ve uygulama başlatılırken değil, veritabanı oluşturma ve güncelleme gibi uzun süreli olabilecek işlemleri gerçekleştirir. Tek yapmanız gereken getWritableDatabase()
veya getReadableDatabase()
numaralı telefonu aramak.
Not: Uzun süre çalıştırılabilecekleri için arka plan iş parçacığında getWritableDatabase()
veya getReadableDatabase()
değerini çağırdığınızdan emin olun.
Daha fazla bilgi için Android'de Threading sayfasına bakın.
SQLiteOpenHelper
kullanmak için onCreate()
ve onUpgrade()
geri çağırma yöntemlerini geçersiz kılan bir alt sınıf oluşturun. onDowngrade()
veya onOpen()
yöntemlerini de uygulamak isteyebilirsiniz, ancak bu zorunlu değildir.
Örneğin, yukarıda gösterilen komutların bazılarını kullanan bir SQLiteOpenHelper
uygulamasını burada görebilirsiniz:
Kotlin
class FeedReaderDbHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION) { override fun onCreate(db: SQLiteDatabase) { db.execSQL(SQL_CREATE_ENTRIES) } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { // This database is only a cache for online data, so its upgrade policy is // to simply to discard the data and start over db.execSQL(SQL_DELETE_ENTRIES) onCreate(db) } override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { onUpgrade(db, oldVersion, newVersion) } companion object { // If you change the database schema, you must increment the database version. const val DATABASE_VERSION = 1 const val DATABASE_NAME = "FeedReader.db" } }
Java
public class FeedReaderDbHelper extends SQLiteOpenHelper { // If you change the database schema, you must increment the database version. public static final int DATABASE_VERSION = 1; public static final String DATABASE_NAME = "FeedReader.db"; public FeedReaderDbHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } public void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE_ENTRIES); } public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // This database is only a cache for online data, so its upgrade policy is // to simply to discard the data and start over db.execSQL(SQL_DELETE_ENTRIES); onCreate(db); } public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { onUpgrade(db, oldVersion, newVersion); } }
Veritabanınıza erişmek için SQLiteOpenHelper
alt sınıfınızı örneklendirin:
Kotlin
val dbHelper = FeedReaderDbHelper(context)
Java
FeedReaderDbHelper dbHelper = new FeedReaderDbHelper(getContext());
Bilgileri bir veritabanına yerleştirin
insert()
yöntemine bir ContentValues
nesnesi ileterek veritabanına veri ekleyin:
Kotlin
// Gets the data repository in write mode val db = dbHelper.writableDatabase // Create a new map of values, where column names are the keys val values = ContentValues().apply { put(FeedEntry.COLUMN_NAME_TITLE, title) put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle) } // Insert the new row, returning the primary key value of the new row val newRowId = db?.insert(FeedEntry.TABLE_NAME, null, values)
Java
// Gets the data repository in write mode SQLiteDatabase db = dbHelper.getWritableDatabase(); // Create a new map of values, where column names are the keys ContentValues values = new ContentValues(); values.put(FeedEntry.COLUMN_NAME_TITLE, title); values.put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle); // Insert the new row, returning the primary key value of the new row long newRowId = db.insert(FeedEntry.TABLE_NAME, null, values);
insert()
için ilk bağımsız değişken
basit tablo adıdır.
İkinci bağımsız değişken, çerçeveye ContentValues
boşsa (yani hiç değer put
vermediyseniz) ne yapılacağını bildirir.
Bir sütunun adını belirtirseniz çerçeve bir satır ekler ve bu sütunun değerini null olarak ayarlar. Bu kod örneğinde olduğu gibi null
belirtirseniz çerçeve, değer olmadığında satır eklemez.
insert()
yöntemleri, yeni oluşturulan satırın kimliğini döndürür. Veriler eklenirken bir hata oluştuysa -1 değerini döndürür. Bu durum, veritabanındaki önceden var olan verilerle bir çakışmanız varsa yaşanabilir.
Veritabanındaki bilgileri okuma
Bir veritabanından okumak için query()
yöntemini kullanarak seçim ölçütlerinizi ve istediğiniz sütunları iletin.
Bu yöntem, eklenecek veriler yerine getirmek istediğiniz verileri ("projeksiyon") tanımlayan sütun listesi dışında insert()
ve update()
öğelerini birleştirir. Sorgunun sonuçları size bir Cursor
nesnesinde döndürülür.
Kotlin
val db = dbHelper.readableDatabase // Define a projection that specifies which columns from the database // you will actually use after this query. val projection = arrayOf(BaseColumns._ID, FeedEntry.COLUMN_NAME_TITLE, FeedEntry.COLUMN_NAME_SUBTITLE) // Filter results WHERE "title" = 'My Title' val selection = "${FeedEntry.COLUMN_NAME_TITLE} = ?" val selectionArgs = arrayOf("My Title") // How you want the results sorted in the resulting Cursor val sortOrder = "${FeedEntry.COLUMN_NAME_SUBTITLE} DESC" val cursor = db.query( FeedEntry.TABLE_NAME, // The table to query projection, // The array of columns to return (pass null to get all) selection, // The columns for the WHERE clause selectionArgs, // The values for the WHERE clause null, // don't group the rows null, // don't filter by row groups sortOrder // The sort order )
Java
SQLiteDatabase db = dbHelper.getReadableDatabase(); // Define a projection that specifies which columns from the database // you will actually use after this query. String[] projection = { BaseColumns._ID, FeedEntry.COLUMN_NAME_TITLE, FeedEntry.COLUMN_NAME_SUBTITLE }; // Filter results WHERE "title" = 'My Title' String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?"; String[] selectionArgs = { "My Title" }; // How you want the results sorted in the resulting Cursor String sortOrder = FeedEntry.COLUMN_NAME_SUBTITLE + " DESC"; Cursor cursor = db.query( FeedEntry.TABLE_NAME, // The table to query projection, // The array of columns to return (pass null to get all) selection, // The columns for the WHERE clause selectionArgs, // The values for the WHERE clause null, // don't group the rows null, // don't filter by row groups sortOrder // The sort order );
Üçüncü ve dördüncü bağımsız değişkenler (selection
ve selectionArgs
) bir WHERE ifadesi oluşturmak üzere birleştirilir. Bağımsız değişkenler seçim sorgusundan ayrı olarak sağlandığı için, birleştirilmeden önce atlanırlar. Böylece, seçim ifadeleriniz SQL yerleştirme işleminden etkilenmez. Tüm bağımsız değişkenler hakkında daha fazla bilgi için query()
referansına bakın.
İmleçteki bir satıra bakmak için Cursor
taşıma yöntemlerinden birini kullanın. Bu yöntem, değerleri okumaya başlamadan önce her zaman çağırmanız gerekir. İmleç -1 konumundan başladığından moveToNext()
çağrısı, "okuma konumu"nu sonuçlardaki ilk girişe yerleştirir ve imlecin sonuç grubundaki son girişi geçip geçmediğini döndürür. Her satır için getString()
veya getLong()
gibi Cursor
alma yöntemlerinden birini çağırarak bir sütunun değerini okuyabilirsiniz. "Get" yöntemlerinin her biri için istediğiniz sütunun dizin konumunu iletmeniz gerekir. Bunu, getColumnIndex()
veya getColumnIndexOrThrow()
yöntemini çağırarak alabilirsiniz. Sonuçları yinelemeyi bitirdiğinizde kaynaklarını serbest bırakmak için imleçte close()
çağrısı yapın.
Örneğin, aşağıda imleçte depolanan tüm öğe kimliklerinin nasıl alınacağı ve bir listeye nasıl ekleneceği gösterilmektedir:
Kotlin
val itemIds = mutableListOf<Long>() with(cursor) { while (moveToNext()) { val itemId = getLong(getColumnIndexOrThrow(BaseColumns._ID)) itemIds.add(itemId) } } cursor.close()
Java
List itemIds = new ArrayList<>(); while(cursor.moveToNext()) { long itemId = cursor.getLong( cursor.getColumnIndexOrThrow(FeedEntry._ID)); itemIds.add(itemId); } cursor.close();
Veritabanından bilgi silme
Tablodan satır silmek için delete()
yönteminde satırları tanımlayan seçim ölçütleri sağlamanız gerekir. Sistem, query()
yönteminin seçim bağımsız değişkenleriyle aynı şekilde çalışır. Seçim spesifikasyonunu bir seçim ifadesine ve seçim bağımsız değişkenlerine böler. Bu madde, bakılacak sütunları tanımlar ve ayrıca sütun testlerini birleştirmenize olanak tanır. Bağımsız değişkenler, yan tümceye bağlı olarak test edilecek değerlerdir.
Sonuç, normal bir SQL ifadesiyle aynı şekilde işlenmediği için SQL yerleştirme işleminden etkilenmez.
Kotlin
// Define 'where' part of query. val selection = "${FeedEntry.COLUMN_NAME_TITLE} LIKE ?" // Specify arguments in placeholder order. val selectionArgs = arrayOf("MyTitle") // Issue SQL statement. val deletedRows = db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs)
Java
// Define 'where' part of query. String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?"; // Specify arguments in placeholder order. String[] selectionArgs = { "MyTitle" }; // Issue SQL statement. int deletedRows = db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs);
delete()
yönteminin döndürülen değeri, veritabanından silinen satır sayısını belirtir.
Veritabanı güncelleme
Veritabanı değerlerinizin bir alt kümesini değiştirmeniz gerektiğinde update()
yöntemini kullanın.
Tabloyu güncellemek, insert()
için ContentValues
söz dizimini delete()
için WHERE
söz dizimiyle birleştirir.
Kotlin
val db = dbHelper.writableDatabase // New value for one column val title = "MyNewTitle" val values = ContentValues().apply { put(FeedEntry.COLUMN_NAME_TITLE, title) } // Which row to update, based on the title val selection = "${FeedEntry.COLUMN_NAME_TITLE} LIKE ?" val selectionArgs = arrayOf("MyOldTitle") val count = db.update( FeedEntry.TABLE_NAME, values, selection, selectionArgs)
Java
SQLiteDatabase db = dbHelper.getWritableDatabase(); // New value for one column String title = "MyNewTitle"; ContentValues values = new ContentValues(); values.put(FeedEntry.COLUMN_NAME_TITLE, title); // Which row to update, based on the title String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?"; String[] selectionArgs = { "MyOldTitle" }; int count = db.update( FeedReaderDbHelper.FeedEntry.TABLE_NAME, values, selection, selectionArgs);
update()
yönteminin döndürülen değeri, veritabanında etkilenen satır sayısıdır.
Veritabanı bağlantısını sürdürme
Veritabanı kapatıldığında getWritableDatabase()
ve getReadableDatabase()
yönteminin çağrılması pahalı olduğundan, veritabanı bağlantınızı erişime ihtiyacınız olduğu sürece açık bırakmalısınız. Genellikle en iyi yöntem, çağrı Etkinliğinin onDestroy()
bölümünde veritabanını kapatmaktır.
Kotlin
override fun onDestroy() { dbHelper.close() super.onDestroy() }
Java
@Override protected void onDestroy() { dbHelper.close(); super.onDestroy(); }
Veritabanınızda hata ayıklama
Android SDK, tablo içeriklerine göz atmanızı, SQL komutlarını çalıştırmanızı ve SQLite veri tabanlarında diğer yararlı işlevleri gerçekleştirmenizi sağlayan bir sqlite3
kabuk aracı içerir. Daha fazla bilgi için kabuk komutlarının nasıl gönderileceğine bakın.