Android 如何使用SQLite保存數(shù)據(jù)
簡介
對于重復數(shù)據(jù)或結構化數(shù)據(jù)(例如聯(lián)系信息),將數(shù)據(jù)保存到數(shù)據(jù)庫是理想選擇。android.database.sqlite 軟件包中提供了在 Android 上使用數(shù)據(jù)庫所需的 API。本篇文章介紹在 Android 上使用 SQLite 數(shù)據(jù)庫。
定義架構和協(xié)定
SQL 數(shù)據(jù)庫的主要原則之一是架構,即數(shù)據(jù)庫組織方式的正式聲明。架構反映在你用于創(chuàng)建數(shù)據(jù)庫的 SQL 語句中。您可能會發(fā)現(xiàn)創(chuàng)建伴隨類(稱為協(xié)定類)很有用,該類以系統(tǒng)化、自記錄的方式明確指定了架構的布局。
協(xié)定類是定義 URI、表和列名稱的常量的容器。通過協(xié)定類,您可以在同一軟件包的所有其他類中使用相同的常量。這樣一來,您就可以在一個位置更改列名稱并將其傳播到整個代碼中。
組織協(xié)定類的一種良好方法是將對整個數(shù)據(jù)庫而言具有全局性的定義放入類的根級別。然后,為每個表創(chuàng)建一個內(nèi)部類。每個內(nèi)部類都枚舉相應表的列。
注意:通過實現(xiàn)
BaseColumns接口,您的內(nèi)部類可以繼承名為_ID的主鍵字段。
例如,以下協(xié)定定義了表示 RSS Feed 的單個表的表名稱和列名稱:
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 創(chuàng)建數(shù)據(jù)庫
定義了數(shù)據(jù)庫的結構后,應實現(xiàn)用于創(chuàng)建和維護數(shù)據(jù)庫和表的方法。以下是用于創(chuàng)建和刪除表的一些語句:
// 創(chuàng)建數(shù)據(jù)庫表
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)";
// 刪除數(shù)據(jù)庫表
private static final String SQL_DELETE_ENTRIES =
"DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;就像您在設備的內(nèi)部存儲空間中保存文件一樣,Android 會將您的數(shù)據(jù)庫存儲在您應用的私有文件夾中。您的數(shù)據(jù)很安全,因為在默認情況下,其他應用或用戶無法訪問此區(qū)域。
SQLiteOpenHelper 類包含一組用于管理數(shù)據(jù)庫的實用 API。當您使用此類獲取對數(shù)據(jù)庫的引用時,系統(tǒng)僅在需要時才執(zhí)行可能需要長時間運行的數(shù)據(jù)庫創(chuàng)建和更新操作,而不是在應用啟動期間執(zhí)行。您僅需調用 getWritableDatabase() 或 getReadableDatabase() 即可。
注意:由于這些操作可能會長時間運行,因此請務必在后臺線程中調用
getWritableDatabase()或getReadableDatabase()。
如需使用 SQLiteOpenHelper,請創(chuàng)建一個用于替換 onCreate() 和 onUpgrade() 回調方法的子類。您可能還需要實現(xiàn) onDowngrade() 或 onOpen() 方法,但這些方法并非必需。
例如,下面展示了使用上述一些命令的 SQLiteOpenHelper 實現(xiàn):
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";
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;
public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
// 創(chuàng)建數(shù)據(jù)庫表
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);
}
}如需訪問您的數(shù)據(jù)庫,請實例化 SQLiteOpenHelper 的子類:
FeedReaderDbHelper dbHelper = new FeedReaderDbHelper(getContext());
將信息添加到數(shù)據(jù)庫
通過將 ContentValues 對象傳遞給 insert() 方法,將數(shù)據(jù)插入到數(shù)據(jù)庫中:
// 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()函數(shù)介紹
public long insert (String table,
String nullColumnHack,
ContentValues values)| Parameters | Details |
|---|---|
| table | String: 要插入行的表名,該值不能為空 |
| nullColumnHack | String: 可選;可為null。SQL 不允許在未命名至少一個列名的情況下插入完全為空的記錄。如果提供的值為空,則不知道列名,無法插入空行。如果不設置為空,nullColumnHack 參數(shù)會提供可空的列名,以便在值為空的情況下明確插入 NULL。 |
| values | ContentValues: 該映射包含該行的初始列值。鍵應該是列名,值應該是列值。該值可以為空。 |
| Returns | Details |
|---|---|
| long | 新插入行的行 ID,如果發(fā)生錯誤則為 -1 |
返回新創(chuàng)建行的 ID;如果在插入數(shù)據(jù)時出錯,會返回 -1。如果您的數(shù)據(jù)與數(shù)據(jù)庫中已有的數(shù)據(jù)之間存在沖突,就會出現(xiàn)這種情況。
從數(shù)據(jù)庫中讀取信息
如需從數(shù)據(jù)庫中讀取信息,請使用 query() 方法,向其傳遞您的選擇條件和所需的列。該方法合并了 insert() 和 update() 元素,不過列表定義了要提取的數(shù)據(jù)(“預測值”),而不是要插入的數(shù)據(jù)。查詢結果會包含在 Cursor 對象中返回給您。
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
);delete()函數(shù)介紹
public Cursor query (String table, // 要查詢的表名,不能為空
String[] columns, // 要返回的列的列表。傳遞 null 將返回所有列
String selection, // 聲明要返回哪些行的過濾器,傳遞 null 將返回給定表的所有行
String[] selectionArgs, // 可以在選擇中包含 ?,它將被選擇參數(shù)中的值替換,按照它們在選擇中出現(xiàn)的順序
String groupBy, // 分組過濾器,傳遞 null 將導致行不被分組
String having, // 如果使用行分組,則過濾器聲明游標中包含哪些行組,傳遞 null 將導致包含所有行組
String orderBy) // 對行進行排序,傳遞 null 將使用默認排序順序,該順序可能是無序的第三個參數(shù)和第四個參數(shù)(selection 和 selectionArgs)會合并起來創(chuàng)建一個 WHERE 子句。由于這兩個參數(shù)是與選擇查詢分開提供的,因此它們在合并之前會進行轉義。這樣一來,您的選擇語句就不受 SQL 注入的影響。
如需查看光標中的某一行,請使用 Cursor move 方法之一,您必須始終在開始讀取值之前調用該方法。由于光標從位置 -1 開始,因此調用 moveToNext() 會將“讀取位置”置于結果的第一個條目上,并返回光標是否已經(jīng)過結果集中的最后一個條目。對于每一行,您都可以通過調用 Cursor get 方法之一(例如 getString() 或 getLong())讀取列的值。對于每個 get 方法,您必須傳遞所需列的索引位置,您可以通過調用 getColumnIndex() 或 getColumnIndexOrThrow() 獲取該位置。遍歷結果之后,請對光標調用 close() 以釋放其資源。例如,以下代碼展示了如何獲取存儲在光標中的所有項目 ID 并將其添加到列表中:
List itemIds = new ArrayList<>();
while(cursor.moveToNext()) {
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedEntry._ID));
itemIds.add(itemId);
}
cursor.close();從數(shù)據(jù)庫中刪除信息
如需從表中刪除行,您需要提供選擇條件,以標識 delete() 方法的目標行。該機制與 query() 方法的目標選擇參數(shù)的工作方式相同。它將選擇規(guī)范劃分為選擇子句和選擇參數(shù)。子句定義要查看的列,并允許您合并列測試。參數(shù)是要測試的值,這些值綁定到子句中。由于結果的處理方式與常規(guī) SQL 語句的處理方式不同,因此不受 SQL 注入的影響。
// 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() 方法的返回值表示從數(shù)據(jù)庫中刪除的行數(shù)。
delete()函數(shù)介紹
// return: 如果傳入 whereClause,則影響的行數(shù),否則為 0。要刪除所有行并獲取計數(shù),請傳遞“1”作為 whereClause。
public int delete (String table, // 要操作的表名,不能為空
String whereClause, // 刪除時應用的可選 WHERE 子句。傳遞 null 將刪除所有行。
String[] whereArgs) // 可以在 where 子句中包含 ?s,它將被 whereArgs 中的值替換。這些值將綁定為字符串。如果 whereClause 為 null 或不包含 ?s,則 whereArgs 可能為 null。更新數(shù)據(jù)庫
如果您需要修改數(shù)據(jù)庫值的子集,請使用 update() 方法。
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() 方法的返回值是數(shù)據(jù)庫中受影響的行數(shù)。
update()函數(shù)介紹
public int update (String table, // 要更新的表名,不能為null
ContentValues values, // 從列名到新列值的映射。 null 是一個有效值,將被轉換為 NULL。
String whereClause, // 更新時應用的可選 WHERE 子句。傳遞 null 將更新所有行。
String[] whereArgs) // 可以在 where 子句中包含 ?s,它將被 whereArgs 中的值替換。這些值將綁定為字符串。如果 whereClause 為 null 或不包含 ?s,則 whereArgs 可能為 null。保留數(shù)據(jù)庫連接
由于在數(shù)據(jù)庫關閉時,調用 getWritableDatabase() 和 getReadableDatabase() 的成本比較高,因此只要您有可能需要訪問數(shù)據(jù)庫,就應保持數(shù)據(jù)庫連接處于打開狀態(tài)。通常情況下,最好在發(fā)出調用的 Activity 的 onDestroy() 中關閉數(shù)據(jù)庫。
@Override
protected void onDestroy() {
dbHelper.close();
super.onDestroy();
}調試數(shù)據(jù)庫
Android SDK 提供一個 sqlite3 shell 工具,您可以使用該工具瀏覽表內(nèi)容、運行 SQL 命令以及在 SQLite 數(shù)據(jù)庫中執(zhí)行其他實用操作。
sqlite3 可啟動用于檢查 SQLite 數(shù)據(jù)庫的 sqlite 命令行程序。它包含用于輸出表格內(nèi)容的 .dump 以及用于輸出現(xiàn)有表格的 SQL CREATE 語句的 .schema 等命令。您也可以從命令行執(zhí)行 SQLite 命令,如下所示:
$ adb -s emulator-5554 shell $ sqlite3 /data/data/com.example.app/databases/rssitems.db SQLite version 3.3.12 Enter ".help" for instructions
注意:您必須擁有對文件系統(tǒng)的 root 權限(例如在模擬器上),才能訪問 SQLite 數(shù)據(jù)庫。
到此這篇關于Android 使用SQLite保存數(shù)據(jù)的文章就介紹到這了,更多相關Android SQLite保存數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Android EditText輸入框實現(xiàn)下拉且保存最近5個歷史記錄思路詳解
今天給大家介紹Android EditText輸入框實現(xiàn)下拉且保存最近5個歷史記錄功能,android實現(xiàn)文本框下拉利用sharedpreferences來保存每次app啟動和關閉時已經(jīng)填寫的數(shù)值,具體代碼跟隨小編一起看看吧2021-07-07
Android查看電池電量的方法(基于BroadcastReceiver)
這篇文章主要介紹了Android查看電池電量的方法,結合實例分析了Android使用BroadcastReceiver實現(xiàn)針對電池電量的查詢技巧,需要的朋友可以參考下2016-01-01

