Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 數據存儲之SQLite數據庫

Android 數據存儲之SQLite數據庫

編輯:關於Android編程

前言

Android中有許多的數據存儲方式,如果我們有少量的數據需要存儲,那麼使用:SharedPreferences、文件存儲就可以了。但是如果有大量數據需要進行讀寫,那麼就需要使用到數據庫了。Android中內置了SQLite數據庫,而SQLite數據庫是一個真正輕量級的數據庫,它並沒有後台進程,整個數據庫就對應於一個文件。Android也給我們提供了大量的API,使用起來很方便。

SQLiteDatabase

Android提供了SQLiteDatabase對象來管理數據庫,SQLiteDatabase有提供方法來創建,刪除,執行SQL命令,並執行常見的數據庫管理任務。

SQLiteDatabase提供了如下靜態方法來打開一個文件對應的數據庫:

SQLiteDatabase openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags):
打開path文件所代表的SQLite數據庫。 SQLiteDatabase openOrCreateDatabase(File file, SQLiteDatabase.CursorFactory factory):
打開或創建(如果不存在)file文件所代表的SQLite數據庫。 SQLiteDatabase openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory):
打開或創建(如果不存在)path文件所代表的SQLite數據庫。

當我們獲取到SQLiteDatabase對象之後,就可以調用SQLiteDatabase如下的方法來對數據庫進行操作了:

JAVA方法 釋義 execSQL(String sql) 執行SQL語句 execSQL(String sql, Object[] bindArgs) 執行帶占位符的SQL語句 insert(String table, String nullColumnHack, ContentValues values) 向指定表中插入特定數據 delete(String table, String whereClause, String[] whereArgs) 刪除指定表中的特定數據 update(String table, ContentValues values, String whereClause, String[] whereArgs) 更新指定表中的數據 query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy,String having, String orderBy) 查詢執行表中的數據 query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy,String having, String orderBy, String limit) 查詢執行表中的數據,limit參數控制最多查詢幾條數據 query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs,String groupBy, String having, String orderBy, String limit) 查詢執行表中的數據,distinct 參數表示是否去除重復的值 rawQuery(String sql, String[] selectionArgs) 執行帶占位符的SQL語句查詢 beginTransaction() 開始事務 endTransaction() 結束事務

Android提供了上面的方法,來幫助開發者更“簡便”的對數據庫進行增刪改查。但是其實這些方法完全可以通過SQL語句來完成。而用記上面復雜的參數的時間,就可以來掌握SQL語句了。

上面的方法,都是返回了一個Cursor接口,該接口提供對由數據庫查詢返回的結果集的隨機讀寫訪問,而Cursor同樣提供了如下方法來移動查詢結果的記錄指針:

JAVA方法 釋義 move(int offset) 從當前位置向前或向後移動記錄指針,如果移動成功則返回true moveToFirst() 移動記錄指針到第一行 moveToLast() 移動記錄指針到最後一行 moveToNext() 移動記錄指針到下一行 moveToPrevious() 移動記錄指針到上一行 moveToPosition(int position) 移動記錄指針到指定行 isFirst() 是否指向第一條 isLast() 是否指向最後一條 isBeforeFirst() 是否指向第一條之前 isAfterLast() 是否指向最後一條之後 isNull(int columnIndex) 指定列是否為空(列基數為0) isClosed() 游標是否已關閉 getCount() 總數據項數 getPosition() 返回當前游標所指向的行數 getColumnIndex(String columnName) 返回某列名對應的列索引值 getString(int columnIndex) 返回當前行指定列的值

一旦通過以上方法移動到指定行後,就可以調用Cursor的getXXX()方法來獲取指定列的數據了。

創建數據庫和表

創建數據庫:
// 判斷數據庫文件存放的文件夾是否存在,不存在則創建
String mPath = Environment.getExternalStorageDirectory() + "/db/";
File file = new File(mPath);
if(!file.exists() && !file.isDirectory()){
    // 創建目錄
    file.mkdirs();
}
// 使用靜態方法打開數據庫(不存在則創建),第二個參數用於返回Course工廠,null則表示使用默認工廠。
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(mPath + "blog.db", null);
創建表:
// 執行創建表SQL語句,創建了一個名為blog_info的表
String createSql = "create table blog_info(blog_id integer primary key, blog_name varchar(255), blog_link varchar(255))";
database.execSQL(createSql);

注意:由於數據庫創建在SD卡中,所以需要加上寫入SD卡權限

操作數據庫

在創建好數據庫和表之後就可以對表中的數據進行管理和操作了。我們可以直接通過execSQL()方法執行SQL語句來操作,也可以使用Android給我們直接提供的增刪改查方法。

insert

insert(String table, String nullColumnHack, ContentValues values):
table:想插入數據的表名。 nullColumnHack:代表強行charunull值的數據列列名。當values參數為null或不想包含任何key-value對時該參數有效。 values:代表一行記錄的數據。
插入的數據參數為ContentValues,ContentValues有點類似與Map集合,它也有put(String key, XXX value)方法,其中key為數據列名,getXxx(String key)為取出對應列名的數據。

往剛剛上面創建的數據庫blog_info表中插入一條數據:

ContentValues contentValues = new ContentValues();
contentValues.put("blog_name", "Airsaid");
contentValues.put("blog_link", "http://blog.csdn.net/airsaid");
// line為新添加的行號,該行號是一個內部值,與主鍵id無關,當發生錯誤時,返回-1。
long line = mDatabase.insert("blog_info", null, contentValues);

dalete

delete(String table, String whereClause, String[] whereArgs):
table:代表想刪除數據的表名。 whereClause:滿足該whereClause子句的記錄將會被刪除。 whereArgs:用於為whereClause子句傳入參數。

刪除和”Airsaid”相關的數據:

int num = mDatabase.delete("blog_info", "blog_name like ?", new String[]{"Airsaid"});
Toast.makeText(this, "一共刪除了:" + num + "條數據", Toast.LENGTH_SHORT).show();

update

update(String table, ContentValues values, String whereClause, String[] whereArgs):
table:代表需要更新的表名。 values:代表想更新的數據。 whereClause:滿足該WhereClause子句的數據將會被更新。 whereArgs: 用於為whereClause子句傳入參數。

將所有主鍵大於5的blog_name改為周游:

ContentValues contentValues = new ContentValues();
contentValues.put("blog_name", "周游");
int num = mDatabase.update("blog_info", contentValues, "_id > ?", new String[]{"5"});

query

query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs,String groupBy, String having, String orderBy, String limit):
distinct:是否去除重復記錄。 table:需要執行查詢的表名。 columns:要查詢出來的列名。 selection:查詢條件子句。 selectionArgs:占位符傳入參數。 groupBy:用與控制分組。 having:用於對分組進行排序。 orderBy:用於對記錄進行排序。 limit:用於進行分頁。

由於查詢條件的不確定性,所以query()方法的參數真的是比較長。。感覺建議在寫查詢語句的時候,可以直接使用rawQuery()方法進行查詢。

實例

下面寫一個實例,用戶分別輸入博客名和博客鏈接,點插入後,將數據存儲到數據庫,並用列表展示出來:
* 布局:




    

    
代碼:
public class MainActivity extends AppCompatActivity {

    private String mPath = Environment.getExternalStorageDirectory() + "/db/";
    private static final String DB_NAME = "blog.db";

    private EditText mEdtName;
    private EditText mEdtLink;
    private ListView mListView;
    private SQLiteDatabase mDatabase;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mEdtName = (EditText) findViewById(R.id.edt_blog_name);
        mEdtLink = (EditText) findViewById(R.id.edt_blog_link);
        mListView = (ListView) findViewById(R.id.listView);

        // 判斷數據庫文件存放的文件夾是否存在,不存在則創建
        File file = new File(mPath);
        if(!file.exists() && !file.isDirectory()){
            // 創建目錄
            file.mkdirs();
        }
        // 使用靜態方法打開數據庫(不存在則創建),第二個參數用於返回Course工廠,null則表示使用默認工廠。
        mDatabase = SQLiteDatabase.openOrCreateDatabase(mPath + DB_NAME, null);
        // 執行創建表SQL語句,創建了一個名為blog_info的表
        String createSql = "create table blog_info(_id integer primary key, blog_name varchar(255), blog_link varchar(255))";
        mDatabase.execSQL(createSql);
    }

    /**
     * 插入數據
     */
    public void insert(View v){
        // 獲取用戶輸入信息
        String name = mEdtName.getText().toString();
        String link = mEdtLink.getText().toString();
        // 執行SQL語句插入數據
        mDatabase.execSQL("insert into blog_info values(null, ?, ?)", new String[]{name, link});
        // 填充數據到ListView
        Cursor cursor = mDatabase.rawQuery("select * from blog_info", null);
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.item_listview_blog, cursor
                , new String[]{"blog_name", "blog_link"}, new int[]{R.id.txt_name, R.id.txt_link}
                , CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        mListView.setAdapter(adapter);
    }
}
Item布局:



    

    

運行結果:

事務

數據庫操作,事務是少不了的,而SQLiteDatabase也提供了如下幾個方法來操作事務:
* beginTransaction():開始事務。
* endTransaction():結束事務。
* inTransaction():判斷當前上下文是否處於事務中。
當調用endTransaction()方法結束事務的時候,那麼到底是提交事務還是進行回滾事務呢?這取決於SQLiteDatabase是否調用了:setTransactionSuccessful()方法來設置事務標志,如果在執行事務的時設置了,當事務成功則提交事務,否則程序將回滾事務。

SQLiteOpenHelper

其實在真實項目開發中,很少使用SQLiteDatabase的方法來打開數據庫,而是通過繼承Android給我們提供的SQLiteOpenHelper抽象類來創建。
SQLiteOpenHelper是一個輔助類,用於來幫助我們建立和管理數據庫。我們只需要繼承它,並實現兩個抽象方法:
* onCreate(SQLiteDatabase db):在初次生成數據庫的時候會被調用,用於生成表結構。
* onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):在數據庫版本發生更新時會被調用,oldVersion為舊數據庫版本號,newVersion為新版本數據庫版本號。

方法

SQLiteOpenHelper有如下方法:

JAVA方法 釋義 getWritableDatabase() 以寫的方式打開數據庫對應的SQLiteDatabase對象 getReadableDatabase() 以讀寫的方式打開數據庫對應的SQLiteDatabase對象 getDatabaseName() 返回被打開SQLite數據庫的名稱 onConfigure(SQLiteDatabase db) 正在配置數據庫連接時調用 onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) 當數據庫降級時調用 onOpen(SQLiteDatabase db) 當數據庫已經打開時調用 setWriteAheadLoggingEnabled(boolean enabled) 啟用或者禁用數據庫中使用預寫日記記錄

實例

繼承SQLiteOpenHelper,在onCreate方法中創建數據庫表:
public class MyDatabaseHelper extends SQLiteOpenHelper {

    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // 創建表結構
        db.execSQL("create table dict(_id integer primary key autoincrement, word, detail)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}
布局很簡單,分別為單詞輸入框和釋義輸入框,輸入完成後點擊按鈕保存到數據庫,保存數據後,用戶可以輸入要查詢的生詞進行查詢,點擊查詢將結果作為dialog展示出來。添加生詞的方法如下:
public void add(View v) {
    // 添加生詞
    String word = mEdtWord.getText().toString();
    String detail = mEdtDetail.getText().toString();
    if(TextUtils.isEmpty(word) || TextUtils.isEmpty(detail)){
        Toast.makeText(this, "輸入的數據不能為空", Toast.LENGTH_SHORT).show();
        return;
    }

    SQLiteDatabase database = mDb.getReadableDatabase();
    database.execSQL("insert into dict values(null, ? , ?)", new String[]{word, detail});
    Toast.makeText(this, "添加成功", Toast.LENGTH_SHORT).show();
}

主要是通過SQLiteOpenHelper的 getReadableDatabase()方法獲取了SQLiteDatabase對象。這裡需要注意的是:
getReadableDatabase()方法會先以讀寫方式打開數據庫,如果數據庫的磁盤空間已經滿了,那麼就會打開失敗,然後再嘗試以只讀的方式打開數據庫。
而通過getWritableDatabase()方法,如果磁盤空間已滿,打開時就會出錯。

查詢:
public void seek(View v) {
    // 查看生詞
    String dict = mEdtInput.getText().toString();
    SQLiteDatabase database = mDb.getReadableDatabase();
    Cursor cursor = database.rawQuery("select * from dict where word like ? or detail like ?"
            , new String[]{"%" + dict + "%", "%" + dict + "%"});

    List dicts = new ArrayList<>();
    while (cursor.moveToNext()){
        String word = cursor.getString(1);
        String detail = cursor.getString(2);
        dicts.add("生詞:" + word + " 解釋:" + detail);
    }
    showData(dicts);
}
將結果展示:
private void showData(List dicts) {
    if(dicts.size() < 1) {
        Toast.makeText(this, "沒有找到到該生詞數據", Toast.LENGTH_SHORT).show();
        return;
    }
    String[] strings = dicts.toArray(new String[dicts.size()]);
    for (String string : strings) {
        Log.e("test", string);
    }

    new AlertDialog.Builder(this)
            .setTitle("查詢出來的單詞結果")
            .setItems(dicts.toArray(new String[dicts.size()]), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    dialog.dismiss();
                }
            }).create().show();
}

運行結果:
這裡寫圖片描述

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved