由sqlite在手機上的儲存位置,引發的onCreate在哪裡執行的總結,sqliteoncreate
轉載請註明出處,謝謝:http://blog.csdn.net/harryweasley/article/details/46467495
我們都知道,android為了操作資料庫,一般是繼承SQLiteOpenHelper類,並實現他的三個函數。
如下所示:
package jz.his.db;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteOpenHelper;public class MessageDataBase extends SQLiteOpenHelper {public MessageDataBase(Context context, String name, CursorFactory factory,int version) {super(context, name, factory, version);}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL("create table lgx_table(_id integer primary key autoincrement ," +"name varchar(20),content varchar(40),time varchar(20) ,head varchar(20),isCheck byte)");}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}}
</pre><p>可以看到建立了一個名為lgx_table的表,裡面有一id,name,content等列。</p><p></p>然後在Activity裡,通過getWritableDatabase或者getReadableDatabase()方法來執行個體化一個SQLiteDatabase<p></p><p></p><pre name="code" class="java">MessageDataBasemessageDataBase = new MessageDataBase(context, "lgx", null, 1);SQLiteDatabase database = messageDataBase.getWritableDatabase();
我們可以看到,建立了一個名字為“lgx”的資料庫。
這裡提出一個問題,通過以上的步驟後,資料庫儲存在哪裡了呢?
資料庫儲存在data/data/[your packageName]/databses,
1.如果是模擬器,直接通過Eclipse下,通過這樣的步驟去看 DBMS--->File Explorer-->data---->data--->your packageName
網上很多介紹,我這裡不介紹。
2.如果是真機,首先這個真機是root過了,下載一個Root Explorer。我的測試機是華為榮耀3c。
當我們執行完了以上的步驟後,進入data/data/jz.his.jzhis/databases/會看到這樣的情景。
其實lgx就是我們剛剛建立的資料庫,lgx-journal是資料庫日誌。
現在我們知道了,資料庫儲存的位置了,你以為這就是我寫這篇部落格的目的?繼續往下看吧,嘿嘿。
如果我不想再手機系統記憶體中儲存資料庫,而是想將我的資料庫放在手機sd卡中,那應該怎麼做呢。
首先,我在res/raw中放一個現成的資料庫,待會在代碼裡,將它拷入手機sd卡中。
看下面的代碼:
package com.example.province;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteDatabase.CursorFactory;import android.database.sqlite.SQLiteException;import android.database.sqlite.SQLiteOpenHelper;import android.os.Environment;public class CopyOfCityInfoDataSupport2 {private static CopyOfCityInfoDataSupport2 cityInfoDataSupport;/** * 資料庫在手機裡的路徑 */private static String DATABASE_PATH = Environment.getExternalStorageDirectory() + "/aaaaa/";/** * 資料庫的名稱 */public static final String dbName = "mzk_db";private SQLiteDatabase mSDB;public static CopyOfCityInfoDataSupport2 getInstance(Context context) {initDataBase(context);if (cityInfoDataSupport == null) {cityInfoDataSupport = new CopyOfCityInfoDataSupport2();}return cityInfoDataSupport;}/** * 初試化資料庫 */private static void initDataBase(Context context) {boolean dbExist = checkDataBase();if (dbExist) {} else {// 如果不存在,則將raw裡的資料存入手機sd卡copyDataBase(context);}}/** * 複製資料庫到手機指定檔案夾下 * * @throws IOException */private static void copyDataBase(Context context) {String databaseFilenames = DATABASE_PATH + dbName;File dir = new File(DATABASE_PATH);FileOutputStream os = null;InputStream is = null;// 判斷檔案夾是否存在,不存在就建立一個if (!dir.exists()) {dir.mkdirs();}try {// 得到資料庫的輸出資料流os = new FileOutputStream(databaseFilenames);// 得到資料檔案的輸入資料流is = context.getResources().openRawResource(R.raw.mzk_db);byte[] buffer = new byte[8192];int count = 0;while ((count = is.read(buffer)) != -1) {os.write(buffer, 0, count);os.flush();}// 之所以不在這裡初始化,是因為這邊是靜態方法,而mSDB並沒有設定為靜態,也不推薦設為靜態// mSDB = SQLiteDatabase.openOrCreateDatabase(DATABASE_PATH +// dbName, null);} catch (Exception e) {e.printStackTrace();} finally {try {os.close();is.close();} catch (IOException e) {e.printStackTrace();}}}/** * 判斷資料庫是否存在 * * @return */private static boolean checkDataBase() {SQLiteDatabase checkDB = null;String databaseFilename = DATABASE_PATH + dbName;// 要自己加上try catch方法try {// 返回最新的資料庫checkDB = SQLiteDatabase.openDatabase(databaseFilename, null,SQLiteDatabase.OPEN_READONLY);} catch (SQLiteException e) {// TODO: handle exception}if (checkDB != null) {checkDB.close();}// 如果checkDB為null,則沒有資料庫,返回falsereturn checkDB == null ? false : true;}/** * 查詢所有省份的資訊 * * @return 省份資訊 */public ArrayList<City> queryProvince() {// 建立資料庫的執行個體mSDB = SQLiteDatabase.openOrCreateDatabase(DATABASE_PATH + dbName, null);ArrayList<City> list = new ArrayList<City>();String sql = "select * from fs_province";Cursor cursor = mSDB.rawQuery(sql, null);while (cursor.moveToNext()) {City city = new City();String id = cursor.getString(cursor.getColumnIndex("ProvinceID"));String name = cursor.getString(cursor.getColumnIndex("ProvinceName"));city.setName(name);city.setId(id);list.add(city);}if (cursor != null) {cursor.close();}return list;}public void closeDataBase() {if (mSDB != null) {mSDB.close();}}}
我們看到,如果將資料庫寫到手機sd卡中,都不需要SQLiteOpenHelper類了,而是直接通過
mSDB = SQLiteDatabase.openOrCreateDatabase(DATABASE_PATH + dbName, null);就可以獲得資料庫的執行個體了。
但是這個方法有個缺點,就是不能進行資料庫的升級了。顯然這樣是非常不好的。
那麼如果我們還想用SQLiteOpenHelper,又將其寫到sd卡中,又該怎麼做呢。
下面的這段代碼是有錯誤的,你只需要注意看51行,正是因為下面的代碼,我才研究了onCreate方法到底什麼時候執行。
package jz.his.db;import java.io.BufferedReader;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;import jz.his.jzhis.R;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteException;import android.database.sqlite.SQLiteOpenHelper;import android.os.Environment;import android.util.Log;public class CityInfoDataSupport extends SQLiteOpenHelper{ private final static String TAG = "CityInfoDataSupport"; public static final String dbName = "cityego"; // 資料庫在手機裡的路徑 private static String DATABASE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath()+"/com.bcinfo.pwzs/"; private static int version = 1; private final String GEOCODING_TABLE_NAME = "GEOCODING"; private SQLiteDatabase mSDB = getReadableDatabase(); private static CityInfoDataSupport mDataSupport; Context context; public static CityInfoDataSupport getInstance(Context context) { initDatabse(context); if (mDataSupport == null) { mDataSupport = new CityInfoDataSupport(context); } return mDataSupport; } CityInfoDataSupport(Context context) { super(context, DATABASE_PATH+dbName, null, version); } @Override public void onCreate(SQLiteDatabase db) { executeAssetsSQL(db, "geocoding_create.sql"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = "drop table if exits " + GEOCODING_TABLE_NAME; db.execSQL(sql); onCreate(db); } private void loadSql(SQLiteDatabase db, String schemaName) { InputStream inputS; try { inputS = context.getAssets().open(schemaName); BufferedReader reader = new BufferedReader(new InputStreamReader(inputS)); String sql = null; while ((sql = reader.readLine()) != null) { db.execSQL(sql.replace(";", "")); } reader.close(); reader = null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 讀取資料庫檔案(.sql),並執行sql語句 * */ private void executeAssetsSQL(SQLiteDatabase db, String schemaName) { Log.e("DataSupport", "executeAssetsSQL"); BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(context.getAssets().open(schemaName))); String line; String buffer = ""; while ((line = in.readLine()) != null) { buffer += line; if (line.trim().endsWith(";")) { db.execSQL(buffer.replace(";", "")); buffer = ""; } } } catch (IOException e) { Log.e("db-error", e.toString()); } finally { try { if (in != null) in.close(); } catch (IOException e) { Log.e("db-error", e.toString()); } } } public synchronized void insertCityInfo() { loadSql(mSDB, "geocoding_data.txt"); } public synchronized List<City> queryDataById(String field, String id) { String sql = ""; List<City> cityList = new ArrayList<City>(); if (field.equals("grade")) { sql = "select * from " + GEOCODING_TABLE_NAME + " where grade = ? "; } else if (field.equals("parent")) { sql = "select * from " + GEOCODING_TABLE_NAME + " where parent = ? "; } String[] params = new String[] { id }; Cursor c = mSDB.rawQuery(sql, params); while (c.moveToNext()) { City city = new City(); city.setGbCode(c.getString(c.getColumnIndex("gbcode"))); city.setGbName(c.getString(c.getColumnIndex("gbname"))); city.setGrade(c.getString(c.getColumnIndex("grade"))); city.setLongitude(c.getString(c.getColumnIndex("longtitude"))); city.setLatitude(c.getString(c.getColumnIndex("latitude"))); city.setParent(c.getString(c.getColumnIndex("parent"))); cityList.add(city); } if (c != null) { c.close(); } return cityList; } public void deleteAppTempTraffic() { String sql = "delete from " + GEOCODING_TABLE_NAME; mSDB.execSQL(sql); } public static void initDatabse(Context cntext) { boolean dbExist = checkDataBase(); //判斷資料庫是否存在 不存在就把raw裡的資料庫寫入手機 if (!dbExist) { try { copyDataBase(cntext); } catch (IOException e) { throw new Error("Error copying database"); } } } /** * 判斷資料庫是否存在 * @return false or true */ public static boolean checkDataBase() { SQLiteDatabase checkDB = null; try { String databaseFilename = DATABASE_PATH + dbName; checkDB = SQLiteDatabase.openDatabase(databaseFilename, null, SQLiteDatabase.OPEN_READONLY); } catch (SQLiteException e) { } if (checkDB != null) { checkDB.close(); } return checkDB != null ? true : false; } /** * 複製資料庫到手機指定檔案夾下 * @throws IOException */ public static void copyDataBase(Context context) throws IOException { String databaseFilenames = DATABASE_PATH + dbName; File dir = new File(DATABASE_PATH); FileOutputStream os = null; // 判斷檔案夾是否存在,不存在就建立一個 if (!dir.exists()) { dir.mkdirs(); } try { // 得到資料庫檔案的寫入流 os = new FileOutputStream(databaseFilenames); } catch (FileNotFoundException e) { e.printStackTrace(); } // 得到資料庫檔案的資料流 InputStream is = context.getResources().openRawResource(R.raw.cityego); byte[] buffer = new byte[8192]; int count = 0; try { while ((count = is.read(buffer)) > 0) { os.write(buffer, 0, count); os.flush(); } } catch (IOException e) { } try { is.close(); os.close(); } catch (IOException e) { e.printStackTrace(); } }}
通過上面的這個代碼,我的onCreate方法一直沒有執行。最終經過我多次實驗,我知道了問題所在,所以在這裡進行總結。
那麼onCreate方法到底什麼時候執行呢?
SQLiteOpenHelper的onCreate方法一定是在getReadableDatabase方法之後的
SQLiteDatabase mSDB = getReadableDatabase()這個方法首先檢查手機中,是否有已經存在的資料庫,如果沒有,則執行onCreate方法,如果有,則不執行---->但是,這裡有個前提是,你的supre(context, DATABASE_PATH+dbName, null, version),的第二個參數不能是已存在的資料庫路徑。
我這裡,將第二個參數,弄成了已存在的資料庫檔案,所以onCreate方法永遠不會執行。
那麼當super(context, dbName, null, version);第二個參數正確和並且執行了getReadableDatabase這個方法,才會在系統記憶體有資料庫。
折磨了我一個下午啊啊啊啊。