上一節講了如何使用SharedPreference和File流存儲數據,同時建議使用FileInputStream/FileOutputStream來保存數據。本文將介紹另一種存儲數據的方式--SQLite輕量級數據庫。
SQLite的相關概念
先介紹幾個基本概念知識:
什麼是SQLite:
SQLite是一款輕量級數據庫,它的設計目的是嵌入式,而且它占用的資源非常少,在嵌入式設備中,只需要幾百KB!
SQLite的特性:
輕量級:使用 SQLite 只需要帶一個動態庫,就可以享受它的全部功能,而且那個動態庫的尺寸想當小。
獨立性:SQLite 數據庫的核心引擎不需要依賴第三方軟件,也不需要所謂的“安裝”。
隔離性:SQLite 數據庫中所有的信息(比如表、視圖、觸發器等)都包含在一個文件夾內,方便管理和維護。
跨平台:SQLite 目前支持大部分操作系統,不至電腦操作系統更在眾多的手機系統也是能夠運行,比如:Android。
多語言接口:SQLite 數據庫支持多語言編程接口。
安全性:SQLite 數據庫通過數據庫級上的獨占性和共享鎖來實現獨立事務處理。這意味著多個進程可以在同一時間從同一數據庫讀取數據,但只能有一個可以寫入數據.
優點:
1、能存儲較多的數據;2、能將數據庫文件存放到SD卡中。
什麼是 SQLiteDatabase?
一個 SQLiteDatabase 的實例代表了一個SQLite 的數據庫,通過SQLiteDatabase 實例的一些方法,我們可以執行SQL 語句,對數據庫進行增、刪、查、改的操作。需要注意的是,數據庫對於一個應用來說是私有的,並且在一個應用當中,數據庫的名字也是惟一的。
什麼是 SQLiteOpenHelper?
根據這名字,我們可以看出這個類是一個輔助類。這個類主要生成一個數據庫,並對數據庫的版本進行管理。當在程序當中調用這個類的方法getWritableDatabase(),或者getReadableDatabase()方法的時候,如果當時沒有數據,那麼Android 系統就會自動生成一個數 據庫。SQLiteOpenHelper 是一個抽象類,我們通常需要繼承它,並且實現裡邊的3 個函數。
什麼是 ContentValues 類?
ContentValues 類和Hashmap/Hashtable 比較類似,它也是負責存儲一些名值對,但是它存儲的名值對當中的名是一個String 類型,而值都是基本類型。
什麼是 Cursor?
Cursor 在Android 當中是一個非常有用的接口,通過Cursor 我們可以對從數據庫查詢出來的結果集進行隨 機的讀寫訪問。
OK,基本知識就介紹到這裡。
SQLite實例
下面開始上代碼:還是按照我的一貫風格,代碼中該解釋的地方都已經在代碼中及時注釋和講解了!
順便來張項目截圖:
先給出xml:
XML/HTML代碼
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical" android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <TextView android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="SQL 練習!(如果你使用的SD卡存儲數據方式,為了保證正常操作,請你先點擊創建一張表然後再操作)"
- android:textSize="20sp" android:textColor="#ff0000" android:id="@+id/tv_title" />
- <Button android:id="@+id/sql_addOne" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="插入一條記錄"></Button>
- <Button android:id="@+id/sql_check" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="查詢數據庫"></Button>
- <Button android:id="@+id/sql_edit" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="修改一條記錄"></Button>
- <Button android:id="@+id/sql_deleteOne" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="刪除一條記錄"></Button>
- <Button android:id="@+id/sql_deleteTable" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="刪除數據表單"></Button>
- <Button android:id="@+id/sql_newTable" android:layout_width="fill_parent"
- android:layout_height="wrap_content" android:text="新建數據表單"></Button>
- </LinearLayout>
xml中定義了我們需要練習用到的幾個操作按鈕,這裡不多解釋了,下面看java源碼:先看我們繼承的 SQLiteOpenHelper 類:
Java代碼
- package com.himi;
- import android.content.Context;
- import android.database.sqlite.SQLiteDatabase;
- import android.database.sqlite.SQLiteOpenHelper;
- import android.util.Log;
- /**
- *
- * @author Himi
- * @解釋 此類我們只需要傳建一個構造函數 以及重寫兩個方法就OK啦、
- *
- */
- public class MySQLiteOpenHelper extends SQLiteOpenHelper {
- public final static int VERSION = 1;// 版本號
- public final static String TABLE_NAME = "himi";// 表名
- public final static String ID = "id";// 後面ContentProvider使用
- public final static String TEXT = "text";
- public static final String DATABASE_NAME = "Himi.db";
- public MySQLiteOpenHelper(Context context) {
- // 在Android 中創建和打開一個數據庫都可以使用openOrCreateDatabase 方法來實現,
- // 因為它會自動去檢測是否存在這個數據庫,如果存在則打開,不過不存在則創建一個數據庫;
- // 創建成功則返回一個 SQLiteDatabase對象,否則拋出異常FileNotFoundException。
- // 下面是來創建一個名為"DATABASE_NAME"的數據庫,並返回一個SQLiteDatabase對象
-
- super(context, DATABASE_NAME, null, VERSION);
- }
- @Override
- // 在數據庫第一次生成的時候會調用這個方法,一般我們在這個方法裡邊生成數據庫表;
- public void onCreate(SQLiteDatabase db) {
- String str_sql = "CREATE TABLE " + TABLE_NAME + "(" + ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT + " text );";
- // CREATE TABLE 創建一張表 然後後面是我們的表名
- // 然後表的列,第一個是id 方便操作數據,int類型
- // PRIMARY KEY 是指主鍵 這是一個int型,用於唯一的標識一行;
- // AUTOINCREMENT 表示數據庫會為每條記錄的key加一,確保記錄的唯一性;
- // 最後我加入一列文本 String類型
- // ----------注意:這裡str_sql是sql語句,類似dos命令,要注意空格!
- db.execSQL(str_sql);
- // execSQL()方法是執行一句sql語句
- // 雖然此句我們生成了一張數據庫表和包含該表的sql.himi文件,
- // 但是要注意 不是方法是創建,是傳入的一句str_sql這句sql語句表示創建!!
- }
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // 一般默認情況下,當我們插入 數據庫就立即更新
- // 當數據庫需要升級的時候,Android 系統會主動的調用這個方法。
- // 一般我們在這個方法裡邊刪除數據表,並建立新的數據表,
- // 當然是否還需要做其他的操作,完全取決於游戲需求。
- Log.v("Himi", "onUpgrade");
- }
- }
我喜歡代碼中立即附上解釋,感覺這樣代碼比較讓大家更容易理解和尋找。
下面看最重要的MainActivity中的代碼:
Java代碼
- package com.himi;
- import java.io.File;
- import java.io.IOException;
- import android.app.Activity;
- import android.content.ContentValues;
- import android.database.Cursor;
- import android.database.sqlite.SQLiteDatabase;
- import android.os.Bundle;
- import android.view.View;
- import android.view.Window;
- import android.view.WindowManager;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.TextView;
- // ------------第三種保存方式--------《SQLite》---------
- /**
- * @author Himi
- * @保存方式:SQLite 輕量級數據庫、
- * @優點: 可以將自己的數據存儲到文件系統或者數據庫當中, 也可以將自己的數據存
- * 儲到SQLite數據庫當中,還可以存到SD卡中
- * @注意1:數據庫對於一個游戲(一個應用)來說是私有的,並且在一個游戲當中,
- * 數據庫的名字也是唯一的。
- * @注意2 apk中創建的數據庫外部的進程是沒有權限去讀/寫的,
- * 我們需要把數據庫文件創建到sdcard上可以解決類似問題.
- * @注意3 當你刪除id靠前的數據或者全部刪除數據的時候,SQLite不會自動排序,
- * 也就是說再添加數據的時候你不指定id那麼SQLite默認還是在原有id最後添加一條新數據
- * @注意4 android 中 的SQLite 語法大小寫不敏感,也就是說不區分大小寫;
- *
- */
- public class MainActivity extends Activity implements OnClickListener {
- private Button btn_addOne, btn_deleteone, btn_check, btn_deleteTable,
- btn_edit, btn_newTable;
- private TextView tv;
- private MySQLiteOpenHelper myOpenHelper;// 創建一個繼承SQLiteOpenHelper類實例
- private SQLiteDatabase mysql ;
- //---------------以下兩個成員變量是針對在SD卡中存儲數據庫文件使用
- // private File path = new File("/sdcard/himi");// 創建目錄
- // private File f = new File("/sdcard/himi/himi.db");// 創建文件
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- this.requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.main);
- tv = (TextView) findViewById(R.id.tv_title);
- btn_addOne = (Button) findViewById(R.id.sql_addOne);
- btn_check = (Button) findViewById(R.id.sql_check);
- btn_deleteone = (Button) findViewById(R.id.sql_deleteOne);
- btn_deleteTable = (Button) findViewById(R.id.sql_deleteTable);
- btn_newTable = (Button) findViewById(R.id.sql_newTable);
- btn_edit = (Button) findViewById(R.id.sql_edit);
- btn_edit.setOnClickListener(this);
- btn_addOne.setOnClickListener(this);
- btn_check.setOnClickListener(this);
- btn_deleteone.setOnClickListener(this);
- btn_deleteTable.setOnClickListener(this);
- btn_newTable.setOnClickListener(this);
- myOpenHelper = new MySQLiteOpenHelper(this);// 實例一個數據庫輔助器
- //備注1 ----如果你使用的是將數據庫的文件創建在SD卡中,那麼創建數據庫mysql如下操作:
- // if (!path.exists()) {// 目錄存在返回false
- // path.mkdirs();// 創建一個目錄
- // }
- // if (!f.exists()) {// 文件存在返回false
- // try {
- // f.createNewFile();//創建文件
- // } catch (IOException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
- // }
- }
- @Override
- public void onClick(View v) {
- try {
- //備注2----如果你使用的是將數據庫的文件創建在SD卡中,那麼創建數據庫mysql如下操作:
- // mysql = SQLiteDatabase.openOrCreateDatabase(f, null);
- //備注3--- 如果想把數據庫文件默認放在系統中,那麼創建數據庫mysql如下操作:
- mysql = myOpenHelper.getWritableDatabase(); // 實例數據庫
- if (v == btn_addOne) {// 添加數據
- // ---------------------- 讀寫句柄來插入---------
- // ContentValues 其實就是一個哈希表HashMap, key值是字段名稱,
- //Value值是字段的值。然後 通過 ContentValues 的 put 方法就可以
- //把數據放到ContentValues中,然後插入到表中去!
- ContentValues cv = new ContentValues();
- cv.put(MySQLiteOpenHelper.TEXT, "測試新的數據");
- mysql.insert(MySQLiteOpenHelper.TABLE_NAME, null, cv);
- // inser() 第一個參數 標識需要插入操作的表名
- // 第二個參數 :默認傳null即可
- // 第三個是插入的數據
- // ---------------------- SQL語句插入--------------
- // String INSERT_DATA =
- // "INSERT INTO himi (id,text) values (1, '通過SQL語句插入')";
- // db.execSQL(INSERT_DATA);
- tv.setText("添加數據成功!點擊查看數據庫查詢");
- } else if (v == btn_deleteone) {// 刪除數據
- // ---------------------- 讀寫句柄來刪除
- mysql.delete("himi", MySQLiteOpenHelper.ID + "=1", null);
- // 第一個參數 需要操作的表名
- // 第二個參數為 id+操作的下標 如果這裡我們傳入null,表示全部刪除
- // 第三個參數默認傳null即可
- // ----------------------- SQL語句來刪除
- // String DELETE_DATA = "DELETE FROM himi WHERE id=1";
- // db.execSQL(DELETE_DATA);
- tv.setText("刪除數據成功!點擊查看數據庫查詢");
- } else if (v == btn_check) {// 遍歷數據
- //備注4------
- Cursor cur = mysql.rawQuery("SELECT * FROM "
- + MySQLiteOpenHelper.TABLE_NAME, null);
- if (cur != null) {
- String temp = "";
- int i = 0;
- while (cur.moveToNext()) {//直到返回false說明表中到了數據末尾
- temp += cur.getString(0);
- // 參數0 指的是列的下標,這裡的0指的是id列
- temp += cur.getString(1);
- // 這裡的0相對於當前應該是咱們的text列了
- i++;
- temp += " "; // 這裡是我整理顯示格式 ,呵呵~
- if (i % 3 == 0) // 這裡是我整理顯示格式 ,呵呵~
- temp += "/n";// 這裡是我整理顯示格式 ,呵呵~
- }
- tv.setText(temp);
- }
- } else if (v == btn_edit) {// 修改數據
- // ------------------------句柄方式來修改 -------------
- ContentValues cv = new ContentValues();
- cv.put(MySQLiteOpenHelper.TEXT, "修改後的數據");
- mysql.update("himi", cv, "id " + "=" + Integer.toString(3), null);
- // ------------------------SQL語句來修改 -------------
- // String UPDATA_DATA =
- // "UPDATE himi SET text='通過SQL語句來修改數據' WHERE id=1";
- // db.execSQL(UPDATA_DATA);
- tv.setText("修改數據成功!點擊查看數據庫查詢");
- } else if (v == btn_deleteTable) {// 刪除表
- mysql.execSQL("DROP TABLE himi");
- tv.setText("刪除表成功!點擊查看數據庫查詢");
- } else if (v == btn_newTable) {// 新建表
- String TABLE_NAME = "himi";
- String ID = "id";
- String TEXT = "text";
- String str_sql2 = "CREATE TABLE " + TABLE_NAME + "(" + ID
- + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT
- + " text );";
- mysql.execSQL(str_sql2);
- tv.setText("新建表成功!點擊查看數據庫查詢");
- }
- // 刪除數據庫:
- // this.deleteDatabase("himi.db");
- } catch (Exception e) {
- tv.setText("操作失敗!");
- } finally {// 如果try中異常,也要對數據庫進行關閉
- mysql.close();
- }
- }
- }
以上代碼中我們實現了兩種存儲方式:
一種存儲默認系統路徑/data-data-com.himi-databases下,另外一種則是保存在了/sdcard-himi下,生成數據庫文件himi.db。
那麼這裡兩種實現方式大概步驟和區別說下:
———–如果我們使用默認系統路徑存儲數據庫文件:
第一步:新建一個類繼承SQLiteOpenHelper;寫一個構造,重寫兩個函數!
第二步:在新建的類中的onCreate(SQLiteDatabase db) 方法中創建一個表;
第三步:在進行刪除數據、添加數據等操作的之前我們要得到數據庫讀寫句柄得到一個數據庫實例;
注意: 繼承寫這個輔助類,是為了在我們沒有數據庫的時候自動為我們生成一個數據庫,並且生成數據庫文件,這裡也同時創建了一張表,因為我們在onCreate裡是在數據庫中創建一張表的操作;這裡還要注意在我們new 這個我們這個MySQLiteOpenHelper 類實例對象的時候並沒有創建數據庫喲~!而是在我們調用(備注3)MySQLiteOpenHelper ..getWritableDatabase() 這個方法得到數據庫讀寫句柄的時候,android 會分析是否已經有了數據庫,如果沒有會默認為我們創建一個數據庫並且在系統路徑data-data-com.himi-databases下生成himi.db 文件!(如果我們使用sd卡存儲數據庫文件,就沒有必要寫這個類了,而是我們自己Open自己的文件得到一個數據庫,反而方便~ )
———–如果我們需要把數據庫文件存儲到SD卡中:
第一步:確認模擬器存在SD卡,關於SD卡的兩種創建方法見Android游戲開發10:TraceView效率檢視工具詳解和兩種創建SDCard的方式。
第二步:(備注1)先創建SD卡目錄和路徑已經我們的數據庫文件!這裡不像上面默認路徑中的那樣,如果沒有數據庫會默認系統路徑生成一個數據庫和一個數據庫文件!我們必須手動創建數據庫文件!
第三步:在進行刪除數據、添加數據等操作的之前我們要得到數據庫讀寫句柄得到一個數據庫實例;(備注2)此時的創建也不是像系統默認創建,而是我們通過打開第一步創建好的文件得到數據庫實例。這裡僅僅是創建一個數據庫!
第四步:在進行刪除數據、添加數據等操作的之前我們還要創建一個表!
第五步:在配置文件AndroidMainfest.xml 聲明寫入SD卡的權限,上一篇已經介紹權限了,不知道的自己去看下吧。
有些童鞋不理解什麼默認路徑方式中就有表?那是因為我們在它默認給我們創建數據庫的時候我們有創建表的操作,就是MySQLiteOpenHelper類中的onCreate()方法裡的操作!所以我們如果要在進行刪除數據、添加數據等操作的之前還要創建一個表,創建表的方法都是一樣的。
總結:不管哪種方式我們都要-創建數據庫-創建表-然後進行操作!
備注4:
在Android中查詢數據是通過Cursor類來實現的,當我們使用SQLiteDatabase.query()方法時,會得到一個Cursor對象,Cursor指向的就是每一條數據。它提供了很多有關查詢的方法,具體方法如下:
以下是方法和說明:
move 以當前的位置為參考,將Cursor移動到指定的位置,成功返回true, 失敗返回false
moveToPosition 將Cursor移動到指定的位置,成功返回true,失敗返回false
moveToNext 將Cursor向前移動一個位置,成功返回true,失敗返回false
moveToLast 將Cursor向後移動一個位置,成功返回true,失敗返回 false。
movetoFirst 將Cursor移動到第一行,成功返回true,失敗返回false
isBeforeFirst 返回Cursor是否指向第一項數據之前
isAfterLast 返回Cursor是否指向最後一項數據之後
isClosed 返回Cursor是否關閉
isFirst 返回Cursor是否指向第一項數據
isLast 返回Cursor是否指向最後一項數據
isNull 返回指定位置的值是否為null
getCount 返回總的數據項數
getInt 返回當前行中指定的索引數據
對於SQLite的很多童鞋有接觸過,但是就不知道怎麼存儲在SD中,所以我也研究了下,這篇也寫了把sd卡中的方式也提供給大家。