2016-07-17 3 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" /> 

을 BTW : 나는 사전 구축 된 데이터베이스를 만들 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();이 실행될 때 두 번째로 SQLiteReadOnlyDatabaseException이 발생합니다. DBAdapter를 초기화 한 원래 활동이 다시 시작됩니다. 이제 어댑터가 다시 초기화되고 onUpgrade 메서드가 호출되지 않으므로 SQLiteReadOnlyDatabaseException이 발생하지 않습니다.

이 모든 과정은 매우 빨라지고 내 경험에 나쁜 영향을 미치지 않습니다.

참고 : new DBAdapter(ctx);은 필요하지 않은 것 같으며 deleteDatabase는 어댑터를 다시 만드는 것으로 보입니다. 하지만주의해서이 코드를 작성했습니다.

이 오류의 원인과 해결 방법에 대한 정보를 얻고 싶습니다.

1

Android SQLite 데이터베이스와 비슷한 문제가 있습니다. 오래 전에 https://code.google.com/p/android/issues/detail?id=174566에 버그 보고서를 제출했습니다. 이 보고서는 이유에 대한 나의 발견을보다 자세하게 논의합니다. 귀하의 문제와 관련이 있는지 확실하지 않지만, 몇 가지 특성을 공유하는 것으로 보입니다.

요약하면 안드로이드는 데이터베이스 파일을 열고 onUpgrade()를 호출하고 onUpgrade() 호출 중에 데이터베이스 파일을 교체하면 안드로이드 사이드 파일 핸들이 이전 파일을 가리키고 이로 인해 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()에서 아무 것도하지 않는 것이 좋습니다.

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의 코드() :

DBReader 관심의 주요 코드이되는 내 자신의 클래스입니다 이야기가 짧게 만들기 위해 그래서

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

, 방금 onUpgrade()를 피하고 내 자신의 사용자 지정 업그레이드 기능을 구현했습니다. 이렇게하면 onUpgrade()에서 데이터베이스가 변경되어 발생하는 오래된 파일 핸들이나 잘못된 파일 핸들에서 Android OS 충돌 문제를 피할 수 있습니다.

데이터베이스를 업그레이드 할 수있는 기능으로 데이터베이스 파일을 실제로 업그레이드하면 OS가 응용 프로그램을 중단하게하는 onUpgrade()가 있습니다. 그리고 버그 리포트에 대한 Google의 의견은 몇 년 후에 만들어 졌으므로 개념을 쉽게 증명할 수 있도록 원래의 충돌 코드가 더 이상 존재하지 않습니다.

데이터베이스 파일을 복사하지 않아도 문제가 다소 다를 수 있지만 여전히 수정 된 것처럼 보이므로 근본 원인이 비슷할 수 있습니다.

+0

내 문제는 당신과 똑같습니다. 오류를 피하려면 솔루션이 좋습니다. 오류를 잡아 내고 새로운 컨텍스트 (이전 컨텍스트를 다시 사용하지 않음)로 클래스를 다시 초기화하면 문제가 쉽게 해결된다는 것을 알게되었습니다. – suku

관련 문제