問題焦點:拷貝的內置數據庫,在後續的使用時,拋出了 Can't upgrade read-only database from version 0 to 1的異常,肯定不存在sql錯誤。 java
解決方案: 拷貝數據庫時,順便升級下數據的版本信息 android
此次的android的app開發有個內置數據庫的功能,而在此以前,我在本地也經過sql建了一個數據庫,爲保持兼容性,我只添加了一個是否使用內置數據的功能,使用內置數據庫時,只需將apk中的數據庫文件覆蓋下data/data/<package_name/>下的文件便可,代碼以下: sql
/** * this method should be invoke in another thread except UI thread * @throws IOException */ private void copyDataBase() throws IOException { MyUtil.log(DBConfig.DB_TAG, "內置數據庫之copyDatabase"); // Open your local db as the input stream InputStream myInput = mContext.getAssets().open(DBConfig.DATABASE_NAME); // Path to the just created empty db String outFileName = DB_PATH + DBConfig.DATABASE_NAME; // Open the empty db as the output stream OutputStream myOutput = new FileOutputStream(outFileName); // transfer bytes from the inputfile to the outputfile byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer)) > 0) { myOutput.write(buffer, 0, length); } // Close the streams myOutput.flush(); myOutput.close(); myInput.close(); }採用這種方法後,首次調用後,初始化了dbhelper後,倒能正常使用,但從第二次開始,就出現了:
SQLiteException: Can't upgrade read-only database from version 1 to 2 數據庫
網上關於這個異常的說法不少,通常是sql語句錯誤居多,但不適合個人這個場景,我不是初次建數據庫,而是使用一個正常內置數據庫,首次能讀寫,就說明sql不可能有問題的。 promise
對於個人這個異常,跟蹤代碼,最後發現,原來內置的數據庫在拷貝時,並未保存數據庫的版本信息,也即版本爲0,當第二次初始化sqlitehelper時,android內部的sqlitehelper便會再次調用oncreate,因而,內置的數據庫表已存在,不能再次更新,便拋出了這個異常,知道了緣由,就有解決方案了:拷貝數據時,順帶升級下數據庫版本便可: app
public void updateVersion(){ SQLiteDatabase checkDB = null; try { String myPath = DB_PATH + DBConfig.DATABASE_NAME; checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE); checkDB.beginTransaction(); int version = checkDB.getVersion(); checkDB.setVersion(DBConfig.DATABASE_VERSION); checkDB.setTransactionSuccessful(); MyUtil.log(DBConfig.DB_TAG, "修改數據庫版本信息 成功"); } catch (SQLiteException e) { // database does't exist yet. } finally { if (checkDB != null) { checkDB.endTransaction(); checkDB.close(); } } }總的使用方法是:
/** * Creates a empty database on the system and rewrites it with your own * database. * * you should promise this methods be used only once. * */ public void createDataBase() throws IOException { MyUtil.log(DBConfig.DB_TAG, "內置數據庫之createDataBase"); //boolean dbExist = checkDataBase(); try { copyDataBase(); MyUtil.log(DBConfig.DB_TAG, "內置數據庫之 修改數據庫版本信息"); updateVersion(); } catch (IOException e) { throw new Error("Error copying database:" + e.getMessage()); } }我採用這個方法,解決個人問題,但願對你們有幫助。