Android 如何使用SQLite保存數(shù)據(jù)
簡介
對于重復(fù)數(shù)據(jù)或結(jié)構(gòu)化數(shù)據(jù)(例如聯(lián)系信息),將數(shù)據(jù)保存到數(shù)據(jù)庫是理想選擇。android.database.sqlite
軟件包中提供了在 Android 上使用數(shù)據(jù)庫所需的 API。本篇文章介紹在 Android 上使用 SQLite
數(shù)據(jù)庫。
定義架構(gòu)和協(xié)定
SQL 數(shù)據(jù)庫的主要原則之一是架構(gòu),即數(shù)據(jù)庫組織方式的正式聲明。架構(gòu)反映在你用于創(chuàng)建數(shù)據(jù)庫的 SQL 語句中。您可能會發(fā)現(xiàn)創(chuàng)建伴隨類(稱為協(xié)定類)很有用,該類以系統(tǒng)化、自記錄的方式明確指定了架構(gòu)的布局。
協(xié)定類是定義 URI、表和列名稱的常量的容器。通過協(xié)定類,您可以在同一軟件包的所有其他類中使用相同的常量。這樣一來,您就可以在一個位置更改列名稱并將其傳播到整個代碼中。
組織協(xié)定類的一種良好方法是將對整個數(shù)據(jù)庫而言具有全局性的定義放入類的根級別。然后,為每個表創(chuàng)建一個內(nèi)部類。每個內(nèi)部類都枚舉相應(yīng)表的列。
注意:通過實現(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ù)庫的結(jié)構(gòu)后,應(yīng)實現(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;
就像您在設(shè)備的內(nèi)部存儲空間中保存文件一樣,Android 會將您的數(shù)據(jù)庫存儲在您應(yīng)用的私有文件夾中。您的數(shù)據(jù)很安全,因為在默認情況下,其他應(yīng)用或用戶無法訪問此區(qū)域。
SQLiteOpenHelper
類包含一組用于管理數(shù)據(jù)庫的實用 API。當您使用此類獲取對數(shù)據(jù)庫的引用時,系統(tǒng)僅在需要時才執(zhí)行可能需要長時間運行的數(shù)據(jù)庫創(chuàng)建和更新操作,而不是在應(yīng)用啟動期間執(zhí)行。您僅需調(diào)用 getWritableDatabase()
或 getReadableDatabase()
即可。
注意:由于這些操作可能會長時間運行,因此請務(wù)必在后臺線程中調(diào)用
getWritableDatabase()
或getReadableDatabase()
。
如需使用 SQLiteOpenHelper
,請創(chuàng)建一個用于替換 onCreate()
和 onUpgrade()
回調(diào)方法的子類。您可能還需要實現(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 不允許在未命名至少一個列名的情況下插入完全為空的記錄。如果提供的值為空,則不知道列名,無法插入空行。如果不設(shè)置為空,nullColumnHack 參數(shù)會提供可空的列名,以便在值為空的情況下明確插入 NULL。 |
values | ContentValues: 該映射包含該行的初始列值。鍵應(yīng)該是列名,值應(yīng)該是列值。該值可以為空。 |
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ù)(“預(yù)測值”),而不是要插入的數(shù)據(jù)。查詢結(jié)果會包含在 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 將導(dǎo)致行不被分組 String having, // 如果使用行分組,則過濾器聲明游標中包含哪些行組,傳遞 null 將導(dǎo)致包含所有行組 String orderBy) // 對行進行排序,傳遞 null 將使用默認排序順序,該順序可能是無序的
第三個參數(shù)和第四個參數(shù)(selection
和 selectionArgs
)會合并起來創(chuàng)建一個 WHERE
子句。由于這兩個參數(shù)是與選擇查詢分開提供的,因此它們在合并之前會進行轉(zhuǎn)義。這樣一來,您的選擇語句就不受 SQL 注入的影響。
如需查看光標中的某一行,請使用 Cursor
move 方法之一,您必須始終在開始讀取值之前調(diào)用該方法。由于光標從位置 -1 開始,因此調(diào)用 moveToNext()
會將“讀取位置”置于結(jié)果的第一個條目上,并返回光標是否已經(jīng)過結(jié)果集中的最后一個條目。對于每一行,您都可以通過調(diào)用 Cursor
get 方法之一(例如 getString()
或 getLong()
)讀取列的值。對于每個 get 方法,您必須傳遞所需列的索引位置,您可以通過調(diào)用 getColumnIndex()
或 getColumnIndexOrThrow()
獲取該位置。遍歷結(jié)果之后,請對光標調(diào)用 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ù)是要測試的值,這些值綁定到子句中。由于結(jié)果的處理方式與常規(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, // 刪除時應(yīng)用的可選 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 是一個有效值,將被轉(zhuǎn)換為 NULL。 String whereClause, // 更新時應(yīng)用的可選 WHERE 子句。傳遞 null 將更新所有行。 String[] whereArgs) // 可以在 where 子句中包含 ?s,它將被 whereArgs 中的值替換。這些值將綁定為字符串。如果 whereClause 為 null 或不包含 ?s,則 whereArgs 可能為 null。
保留數(shù)據(jù)庫連接
由于在數(shù)據(jù)庫關(guān)閉時,調(diào)用 getWritableDatabase()
和 getReadableDatabase()
的成本比較高,因此只要您有可能需要訪問數(shù)據(jù)庫,就應(yīng)保持數(shù)據(jù)庫連接處于打開狀態(tài)。通常情況下,最好在發(fā)出調(diào)用的 Activity 的 onDestroy()
中關(guān)閉數(shù)據(jù)庫。
@Override protected void onDestroy() { dbHelper.close(); super.onDestroy(); }
調(diào)試數(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 權(quán)限(例如在模擬器上),才能訪問 SQLite 數(shù)據(jù)庫。
到此這篇關(guān)于Android 使用SQLite保存數(shù)據(jù)的文章就介紹到這了,更多相關(guān)Android SQLite保存數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android SQLite基本用法詳解
- android中SQLite使用及特點
- Android SQLite數(shù)據(jù)庫連接實現(xiàn)登錄功能
- Android使用gradle讀取并保存數(shù)據(jù)到BuildConfg流程詳解
- Android通過ViewModel保存數(shù)據(jù)實現(xiàn)多頁面的數(shù)據(jù)共享功能
- Android學(xué)習(xí)筆記-保存數(shù)據(jù)到SQL數(shù)據(jù)庫中(Saving Data in SQL Databases)
- Android 實現(xiàn)永久保存數(shù)據(jù)的方法詳解
相關(guān)文章
Android 側(cè)邊滑動關(guān)閉Activity的示例代碼
這篇文章主要介紹了Android 側(cè)邊滑動關(guān)閉Activity的方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05Android EditText輸入框?qū)崿F(xiàn)下拉且保存最近5個歷史記錄思路詳解
今天給大家介紹Android EditText輸入框?qū)崿F(xiàn)下拉且保存最近5個歷史記錄功能,android實現(xiàn)文本框下拉利用sharedpreferences來保存每次app啟動和關(guān)閉時已經(jīng)填寫的數(shù)值,具體代碼跟隨小編一起看看吧2021-07-07android打開應(yīng)用所在的市場頁面進行評分操作的方法
這篇文章主要介紹了android打開應(yīng)用所在的市場頁面進行評分操作的方法,涉及Android操作市場頁面評分效果的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-04-04Android查看電池電量的方法(基于BroadcastReceiver)
這篇文章主要介紹了Android查看電池電量的方法,結(jié)合實例分析了Android使用BroadcastReceiver實現(xiàn)針對電池電量的查詢技巧,需要的朋友可以參考下2016-01-01