2016-07-17 15 views
0

データベースを更新するたびにこのエラーが発生します。しかし、私がそのままアプリを再実行すると、データベースが更新されます。SQLiteReadOnlyDatabaseException書き込み可能データベースのデータベース更新時

android.database.sqlite.SQLiteReadOnlyDatabaseException: attempt to write a readonly database (code 1032)[ 

コード:

public DBAdapter(Context context) { 
    super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    ctx = context; 
    db = getWritableDatabase(); 
} 

@Override 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
    if (oldVersion != newVersion) { 
     ctx.deleteDatabase(DATABASE_NAME); 
     new DBAdapter(ctx); 
    } else { 
     super.onUpgrade(db, oldVersion, newVersion); 
    } 
} 

が提案SOの答えの一つとして、私はこれも追加しました:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 

をところで:私は、構築済みのデータベースを作成するSQLiteAssetHelperを使用しています

+0

なぜすべてのデータベースを削除しますか? – USKMobility

+0

あらかじめ構築されたデータをたくさん送ろうと思います。 – suku

答えて

1

これはこの問題を回避するための解決策ではなく、回避策です。

public DBAdapter(Context context) { 
    super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    ctx = context; 
    try { 
     db = getWritableDatabase(); 
    } catch (SQLiteReadOnlyDatabaseException e){ 
     ctx.startActivity(new Intent(ctx, MainActivity.class)); 
    } 
} 

@Override 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
    if (oldVersion != newVersion) { 
     ctx.deleteDatabase(DATABASE_NAME); 
     new DBAdapter(ctx); 
    } else { 
     super.onUpgrade(db, oldVersion, newVersion); 
    } 
} 

最初にアダプタを初期化すると、書き込み可能なdbが作成されます。その後、onUpgradeが呼び出されます。ここでデータベースが削除されると、アダプタは再初期化されます。しかし、dbの接続は削除されず、したがって、db = getWritableDatabase();が実行されたときに2回目になりますSQLiteReadOnlyDatabaseExceptionが発生します。 DBAdapterを初期化した元のアクティビティが再開されます。アダプタが再初期化され、onUpgradeメソッドが呼び出されないため、SQLiteReadOnlyDatabaseExceptionは発生しません。

このプロセスはすべて非常に高速で、私の場合はユーザーエクスペリエンスが悪くなることはありません。

注:new DBAdapter(ctx);は必要ないと思われ、deleteDatabaseはアダプターを再作成したようです。しかし、慎重に、私はこのコード行を書いています。

私は、このエラーの原因と解決策に関する情報を得たいと考えています。

1

AndroidのSQLiteデータベースにも同様の問題がありました。私はずっと前にhttps://code.google.com/p/android/issues/detail?id=174566にバグレポートを提出しました。この報告書では、その理由についての私の調査結果について詳しく説明します。あなたの問題に関連しているかどうかはわかりませんが、いくつかの特徴を共有しているようです。

ここで要約すると、Androidはデータベースファイルを開き、onUpgrade()を呼び出し、onUpgrade()呼び出し中にデータベースファイルを置き換えると、Android側のファイルハンドルが古いファイルを指し示し、 onUpgrade()から戻ってAndroidが古いファイルにアクセスしようとするとアプリケーションがクラッシュする可能性があります。ここで

は、私は、問題を回避するために使用されるいくつかのコードです:

アプリを起動すると、私は(のonCreateでこれをやった):

Thread t = new Thread(new Runnable() { 
    @Override 
    public void run() { 
    Context context = getApplicationContext(); 
    DBReader.copyDB(MainActivity.this); 
    DBReader.initialize(context); 
    } 
}); 
t.start(); 

これは、データベースファイルの更新が発生する原因となりますバックグラウンドでアプリが起動している間に、ユーザーはすばらしいアプリケーションに畏敬の念を抱いています。私のファイルはかなり大きかったので、コピーにはしばらく時間がかかりました。ここでonUpgrade()で何もしないように注意してください。

DBReaderが関心の主なコードはこれであるために私自身のクラス、次のとおりです、話を短くするために、そう

public static synchronized boolean checkIfInitialized(Context context) { 
    File dbFile = context.getDatabasePath(DBHelper.DB_NAME); 
    return dbFile.exists(); 
} 

SharedPreferences prefs = context.getSharedPreferences(Const.KEY_PREFERENCES, Context.MODE_PRIVATE); 
    //here we have stored the latest version of DB copied 
    String dbVersion = prefs.getString(Const.KEY_DB_VERSION, "0"); 
    int dbv = Integer.parseInt(dbVersion); 
    if (checkIfInitialized(context) && dbv == DBHelper.DB_VERSION) { 
    return; 
    } 
    File target = context.getDatabasePath(DBHelper.DB_NAME); 
    String path = target.getAbsolutePath(); 
    //Log.d("Awesome APP", "Copying database to " + path); 

    path = path.substring(0, path.lastIndexOf("/")); 
    File targetDir = new File(path); 
    targetDir.mkdirs(); 
    //Copy the database from assets 
    InputStream mInput = context.getAssets().open(DBHelper.DB_NAME); 
    OutputStream mOutput = new FileOutputStream(target.getAbsolutePath()); 
    byte[] mBuffer = new byte[1024]; 
    int mLength; 
    while ((mLength = mInput.read(mBuffer)) > 0) { 
    mOutput.write(mBuffer, 0, mLength); 
    } 
    mOutput.flush(); 
    mOutput.close(); 
    mInput.close(); 
    SharedPreferences.Editor edit = prefs.edit(); 
    edit.putString(Const.KEY_DB_VERSION, "" + DBHelper.DB_VERSION); 
    edit.apply(); 

とcheckIfInitializedためのコード()私はonUpgrade()を完全に避け、独自のカスタムアップグレード機能を実装しました。これにより、onUpgrade()のデータベースが変更されたため、古いファイルハンドルや無効なファイルハンドルでAndroid OSがクラッシュする問題を回避できます。

実際にデータベースをアップグレードできるようにする関数でデータベースファイルをアップグレードすると、OSがアプリケーションをクラッシュさせる原因となるonUpgrade()が奇妙になります。そして、バグレポートに関するGoogleのコメントは数年後に作られたので、私はもはやコンセプトを簡単に証明するために元のクラッシュコードがなくなった。

データベースファイルをコピーしていないにもかかわらず、問題が多少異なる可能性がありますが、依然として問題が修正されているように見えるため、根本原因が似ている可能性があります。

+0

私の問題はあなたとまったく同じです。エラーを避けるためには、あなたの解決策は良いです。エラーをキャッチし、新しいコンテキスト(古いコンテキストを再利用しない)でクラスを再初期化すると、問題は簡単に解決されました。 – suku

関連する問題