在實際開發中,我們經常遇到需使用自己已經定制好數據的數據庫,一般的做法是:
1、用Sqlite數據庫工具制作數據庫文件,網上有許多這類工具,可以自己搜索下載,我用的是SqliteStudio。
需要注意的是android對其使用的Sqlite數據庫有一些固定的要求,包括:
(1)數據庫文件中必須有一個名為“android_metadata”的表,這個表只包括一個字段:locale,也只需要一條記錄,默認值為“en_US”。
CREATE TABLE "android_metadata" ("locale" TEXT DEFAULT 'zh_CN') INSERT INTO "android_metadata" VALUES ('zh_CN')
(2)數據庫文件中的其它表,必須包括一個名字“_id”的關鍵字字段,ListView等使用的適配器自動綁定'_id'如果沒有會報錯。
2、將制作好的數據庫文件放在Android項目的assets文件夾或res/raw文件夾下(我習慣放在assets文件夾下)。
3、Android項目使用的數據庫文件一般在/data/data/項目包名/databases/下,使用代碼使程序在運行時進行判斷,如該路徑下沒有指定的文件,則進行復制,否則不做任何操作。
4、如數據庫文件不超過1M,可以直接復制,否則需要預先將數據庫文分割為幾個不超過1M的文件,復制到目標路徑后再組合一一起。
實例:
使用一個DBHelper類來實現判斷和復制數據庫的操作,這個類繼承自SQLiteOpenHelper類。
package com.bluehowk.homecooking; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteOpenHelper; /** * 用法: * DBHelper dbHelper = new DBHelper(this); * dbHelper.createDataBase(); * SQLiteDatabase db = dbHelper.getWritableDatabase(); * Cursor cursor = db.query() * db.execSQL(sqlString); * 注意:execSQL不支持帶;的多條SQL語句 * 見execSQL的源碼注釋 (Multiple statements separated by ;s are not supported.) * 將把assets下的數據庫文件直接復制到DB_PATH,但數據庫文件大小限制在1M以下 * 如果有超過1M的大文件,則需要先分割為N個小文件,然后使用copyBigDatabase()替換copyDatabase() */ public class DBHelper extends SQLiteOpenHelper { //用戶數據庫文件的版本 private static final int DB_VERSION = 1; //數據庫文件目標存放路徑為系統默認位置,cn.arthur.examples 是你的包名 private static String DB_PATH = "/data/data/com.bluehowk.homecooking/databases/"; /* //如果你想把數據庫文件存放在SD卡的話 private static String DB_PATH = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "目標路徑"; */ //下面兩個靜態變量分別是目標文件的名稱和在assets文件夾下的文件名 private static String DB_NAME = "cookdata.db"; private static String ASSETS_NAME = "cookdata.db"; private SQLiteDatabase myDataBase = null; private final Context myContext; /** * 如果數據庫文件較大,使用FileSplit分割為小於1M的小文件 * 此例中分割為 hello.db.101 hello.db.102 hello.db.103 */ //第一個文件名后綴 private static final int ASSETS_SUFFIX_BEGIN = 101; //最后一個文件名后綴 private static final int ASSETS_SUFFIX_END = 103; /** * 在SQLiteOpenHelper的子類當中,必須有該構造函數 * @param context 上下文對象 * @param name 數據庫名稱 * @param factory 一般都是null * @param version 當前數據庫的版本,值必須是整數並且是遞增的狀態 */ public DBHelper(Context context, String name, CursorFactory factory, int version) { //必須通過super調用父類當中的構造函數 super(context, name, null, version); this.myContext = context; } public DBHelper(Context context, String name, int version){ this(context,name,null,version); } public DBHelper(Context context, String name){ this(context,name,DB_VERSION); } public DBHelper (Context context) { this(context, DB_PATH + DB_NAME); } public void createDataBase() throws IOException{ boolean dbExist = checkDataBase(); if(dbExist) { //數據庫已存在,不做任何操作 } else { //創建數據庫 try { File dir = new File(DB_PATH); if(!dir.exists()){ dir.mkdirs(); } File dbf = new File(DB_PATH + DB_NAME); if(dbf.exists()){ dbf.delete(); } SQLiteDatabase.openOrCreateDatabase(dbf, null); // 復制asseets中的數據庫文件到DB_PATH下 copyDataBase(); } catch (IOException e) { throw new Error("數據庫創建失敗"); } } } //檢查數據庫是否有效 private boolean checkDataBase(){ SQLiteDatabase checkDB = null; String myPath = DB_PATH + DB_NAME; try{ checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); }catch(SQLiteException e){ //database does't exist yet. } if(checkDB != null){ checkDB.close(); } return checkDB != null ? true : false; } /** * 復制assets文件中的數據庫到指定路徑 * 使用輸入輸出流進行復制 **/ private void copyDataBase() throws IOException{ InputStream myInput = myContext.getAssets().open(ASSETS_NAME); String outFileName = DB_PATH + DB_NAME; OutputStream myOutput = new FileOutputStream(outFileName); byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer))>0){ myOutput.write(buffer, 0, length); } myOutput.flush(); myOutput.close(); myInput.close(); } //復制assets下的大數據庫文件時用這個 private void copyBigDataBase() throws IOException{ InputStream myInput; String outFileName = DB_PATH + DB_NAME; OutputStream myOutput = new FileOutputStream(outFileName); for (int i = ASSETS_SUFFIX_BEGIN; i < ASSETS_SUFFIX_END+1; i++) { myInput = myContext.getAssets().open(ASSETS_NAME + "." + i); byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer))>0){ myOutput.write(buffer, 0, length); } myOutput.flush(); myInput.close(); } myOutput.close(); } @Override public synchronized void close() { if(myDataBase != null){ myDataBase.close(); } super.close(); } @Override public void onCreate(SQLiteDatabase db) { } /** * 數據庫創建時執行,如果不是預制的數據庫,可以在這些寫一些創建表和添加初始化數據的操作 * 如:db.execSQL("create table cookdata (_id integer primary key,cook_name * varchar(20),cook_sort varchar(20))"); */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { /** * 數據庫升級時執行,前面我們定義的DB_VERSION就是數據庫版本,在版本升高時執行 * 一般做一些數據備份和恢復到新數據庫的操作。 */ } }
可以使用如下代碼進行調用:
helper=new DBHelper(context); try { helper.createDataBase(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }