天天看點

【Android遊戲開發十三】(儲存遊戲資料 [下文])詳解SQLite存儲方式

     上一篇跟各位童鞋介紹了SharedPreference 和 File流如何存儲資料,并且推薦使用FileOutputStream/FileInputStream來存儲咱們遊戲資料,那麼這一篇則是像大家介紹另外一種适合遊戲資料存儲的方式: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,基本知識就介紹到這裡,下面開始上代碼:還是按照我的一貫風格,代碼中該解釋的地方都已經在代碼中及時注釋和講解了!

順便來張項目截圖: 

<a target="_blank" href="http://blog.51cto.com/attachment/201107/212520931.png"></a>

 先給出xml: 

&lt;?xml version="1.0" encoding="utf-8"?&gt; 

&lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 

    android:orientation="vertical" android:layout_width="fill_parent" 

    android:layout_height="fill_parent"&gt; 

    &lt;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" /&gt; 

    &lt;Button android:id="@+id/sql_addOne" android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:text="插入一條記錄"&gt;&lt;/Button&gt; 

    &lt;Button android:id="@+id/sql_check" android:layout_width="fill_parent"   

        android:layout_height="wrap_content" android:text="查詢資料庫"&gt;&lt;/Button&gt; 

    &lt;Button android:id="@+id/sql_edit" android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:text="修改一條記錄"&gt;&lt;/Button&gt; 

    &lt;Button android:id="@+id/sql_deleteOne" android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:text="删除一條記錄"&gt;&lt;/Button&gt; 

    &lt;Button android:id="@+id/sql_deleteTable" android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:text="删除資料表單"&gt;&lt;/Button&gt; 

    &lt;Button android:id="@+id/sql_newTable" android:layout_width="fill_parent" 

        android:layout_height="wrap_content" android:text="建立資料表單"&gt;&lt;/Button&gt; 

&lt;/LinearLayout&gt; 

      xml中定義了我們需要練習用到的幾個操作按鈕,這裡不多解釋了,下面看java源碼:先看我們繼承的 SQLiteOpenHelper 類 

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語句表示建立!!  

    }  

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

        // 一般預設情況下,當我們插入 資料庫就立即更新  

        // 當資料庫需要更新的時候,Android 系統會主動的調用這個方法。  

        // 一般我們在這個方法裡邊删除資料表,并建立新的資料表,  

        // 當然是否還需要做其他的操作,完全取決于遊戲需求。  

        Log.v("Himi", "onUpgrade");  

}   

      我喜歡代碼中立即附上解釋,感覺這樣代碼比較讓大家更容易了解和尋找,當然如果童鞋們不喜歡,可以告訴我,我改~嘿嘿~

     下面看最重要的MainActivity中的代碼: 

import java.io.File;  

import java.io.IOException;  

import android.app.Activity;  

import android.content.ContentValues;  

import android.database.Cursor;  

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》---------  

 * @儲存方式: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");// 建立檔案  

    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();  

//          }  

//      }   

    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) {// 修改資料  

                // ------------------------句柄方式來修改 -------------  

                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 2D遊戲開發之十】

    第二步:(備注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卡中的方式也提供給大家。

     OK 這元旦放假幾天就光給大家寫這個了,呵呵~淩晨2點了,咳咳~該睡覺了。(我一般淩成3點睡覺,早8點起來上班 呵呵~習慣了~)

本文轉自 xiaominghimi 51CTO部落格,原文連結:http://blog.51cto.com/xiaominghimi/606759,如需轉載請自行聯系原作者