2013-08-24 2 views
2

다른 유사한 질문을했지만 답변을 얻지 못했습니다.SQLite 디스크 IO 예외이며 데이터베이스 예외를 열 수 없습니다.

내 안드로이드 앱에서 미리 빌드 된 데이터베이스를 열어두고 있습니다. 자산 폴더에 있으며 SQLiteOpenHelper (아직없는 경우)을 사용하여 복사됩니다. 이 클래스 :

import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 

import android.content.Context; 
import android.database.SQLException; 
import android.database.sqlite.SQLiteDatabase; 
import android.database.sqlite.SQLiteOpenHelper; 

public class ExternalDbOpenHelper extends SQLiteOpenHelper { 

public static String DB_PATH; 
public static String DB_NAME; 
public SQLiteDatabase database; 
public final Context context; 

public SQLiteDatabase getDb() { 
    return database; 
} 

public ExternalDbOpenHelper(Context context, String databaseName) { 
    super(context, databaseName, null, 1); 
    this.context = context; 

    String packageName = context.getPackageName(); 
    DB_PATH = String.format("//data//data//%s//databases//", packageName); 
    DB_NAME = databaseName; 
    openDataBase(); 
} 

public void createDataBase() { 
    boolean dbExist = checkDataBase(); 
    if (!dbExist) { 
     this.getReadableDatabase(); 
     try { 
      copyDataBase(); 
     } catch (IOException e) { 
      // Log.e(this.getClass().toString(), "Copying error"); 
      //throw new Error("Error copying database!"); 
     } 
    } else { 
     // Log.i(this.getClass().toString(), "Database already exists"); 
    } 
} 

private boolean checkDataBase() { 
    SQLiteDatabase checkDb = null; 
    try { 
     String path = DB_PATH + DB_NAME; 
     checkDb = SQLiteDatabase.openDatabase(path, null, 
       SQLiteDatabase.OPEN_READONLY); 
    } catch (SQLException e) { 
     // Log.e(this.getClass().toString(), "Error while checking db"); 
    } 

    if (checkDb != null) { 
     checkDb.close(); 
    } 
    return checkDb != null; 
} 

private void copyDataBase() throws IOException { 

    InputStream externalDbStream = context.getAssets().open(DB_NAME); 

    String outFileName = DB_PATH + DB_NAME; 

    OutputStream localDbStream = new FileOutputStream(outFileName); 

    byte[] buffer = new byte[1024]; 
    int bytesRead; 
    while ((bytesRead = externalDbStream.read(buffer)) > 0) { 
     localDbStream.write(buffer, 0, bytesRead); 
    } 

    localDbStream.close(); 
    externalDbStream.close(); 

} 

public SQLiteDatabase openDataBase() throws SQLException { 
    String path = DB_PATH + DB_NAME; 
    if (database == null) { 
     createDataBase(); 
     database = SQLiteDatabase.openDatabase(path, null, 
       SQLiteDatabase.OPEN_READWRITE); //caused by this line 
    } 
    return database; 
} 

@Override 
public synchronized void close() { 
    if (database != null) { 
     database.close(); 
    } 
    super.close(); 
} 

@Override 
public void onCreate(SQLiteDatabase db) { 
} 

@Override 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
} 
} 

그리고 이것은 내 활동에 : 내 응용 프로그램에서

private static final String DB_NAME = "myDB.sqlite"; 
private SQLiteDatabase database; 
private ExternalDbOpenHelper dbOpenHelper; 

//in onCreate() 
dbOpenHelper = new ExternalDbOpenHelper(this,DB_NAME); 
database = dbOpenHelper.openDataBase(); 

나는 반복적으로 커서rawQuery을 사용하여 데이터베이스를 쿼리합니다. 데이터베이스를 OPEN_READONLY 열어 본다. 그래서 이전에는 그것을 닫지 않았습니다. 이 이제 추가 :

@Override 
protected void onDestroy() 
{ 
    dbOpenHelper.close(); 
    super.onDestroy(); 

} 

이 문제인가? 필자는 SQLite 디스크 입출력 예외를 경험하지 못했고 전에 데이터베이스 예외를 열 수 없었습니다 (dbOpenHelper.close();없이. 충돌 보고서에서 한 번씩보고되었습니다). 두 배 앱은 출시에 추락 theExternalDbOpenHelper 클래스의 라인 수 OpenDatabase에서

database = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READWRITE);

()에 의해 발생했다.

오류를 재현 할 수 없습니다. 보고 한 두 장치는 장치 이름이 "기타"로 비어 있습니다. 이 이것

android.database.sqlite.SQLiteCantOpenDatabaseException 
in android.database.sqlite.SQLiteDatabase.dbopen: 

java.lang.RuntimeException: Unable to start activity  ComponentInfo{com.technicosa.unjumble/com.technicosa.unjumble.MainActivity}: android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981) 
at android.app.ActivityThread.access$600(ActivityThread.java:123) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:137) 
at android.app.ActivityThread.main(ActivityThread.java:4424) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:511) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 
at dalvik.system.NativeStart.main(Native Method) 
Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unable to open database file 
at android.database.sqlite.SQLiteDatabase.dbopen(Native Method) 
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1013) 
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:986) 
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:1024) 
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:986) 
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:962) 
at com.technicosa.unjumble.dbhelper.ExternalDbOpenHelper.openDataBase(ExternalDbOpenHelper.java:90) 
at com.technicosa.unjumble.dbhelper.ExternalDbOpenHelper.<init>(ExternalDbOpenHelper.java:33) 
at com.technicosa.unjumble.MainActivity.onCreate(MainActivity.java:131) 
at android.app.Activity.performCreate(Activity.java:4465) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920) 
... 11 more 
+0

을 [이] (http://stackoverflow.com/a/4828540/739270) 코드를 디버깅하는 동안 많은 도움이됩니다 충돌 로그를 공유하는 원인 –

+1

수 있습니다. 보고 된 로그를 공유하십시오. 내가 코드에 대해 가장 의심하는 것은 데이터베이스 ** 경로 **입니다. Nexus S, HTC와 같은 많은 기기에서 IO를 사용할 수있는 방법입니다. 데이터 디렉토리가 다를 수 있으므로'Environment.getDataDirectory() + "/ data/YOUR_PACKAGE/databases /"; '를 사용해보십시오. –

+0

스택 추적을 게시했습니다. –

답변

0

봐이 매력

public class SmartOpenHelper extends SQLiteOpenHelper { 

    private Context context; 
    private SQLiteDatabase myDataBase; 
    private String DB_SQL; 
    private SmartVersionHandler smartVersionHandler; 

    SmartOpenHelper(Context context, String dbname, int dbversion, String dbSqlName, SmartVersionHandler smartVersionHandler) throws IOException { 
     super(context, dbname, null, dbversion); 
     this.context = context; 
     this.DB_SQL = dbSqlName; 
     this.smartVersionHandler = smartVersionHandler; 
    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 
     try { 
      BufferedInputStream inStream = new BufferedInputStream(context.getAssets().open(DB_SQL)); 
      String sql = ""; 
      int character = -2; 
      do { 
       character = inStream.read(); 
       if ((character != -1) && (character != -2)) 
        sql += (char) character; 
       else 
        break; 
      } while (true); 
      System.out.println("onCreate DB SQL = " + sql.split("\n")); 
      String[] arrSQL = sql.split("\n"); 

      for (int i = 0; i < arrSQL.length; i++) { 
       db.execSQL(arrSQL[i]); 
      } 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     if (this.smartVersionHandler != null) { 
      this.smartVersionHandler.onInstalling(SmartApplication.REF_SMART_APPLICATION); 
     } 
    } 

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 

     try { 
      BufferedInputStream inStream = new BufferedInputStream(context.getAssets().open(DB_SQL)); 
      String sql = ""; 
      int character = -2; 
      do { 
       character = inStream.read(); 
       if ((character != -1) && (character != -2)) 
        sql += (char) character; 
       else 
        break; 
      } while (true); 

      System.out.println("onUpgrade DB SQL = " + sql.split("\n")); 
      String[] arrSQL = sql.split("\n"); 
      for (int i = 0; i < arrSQL.length; i++) { 
       db.execSQL(arrSQL[i]); 
      } 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     if (this.smartVersionHandler != null) { 
      this.smartVersionHandler.onUpgrading(oldVersion, newVersion, SmartApplication.REF_SMART_APPLICATION); 
     } 
    } 

    public SQLiteDatabase getOpenDatabase() { 
     return myDataBase; 
    } 

    public synchronized void close() { 
     if (myDataBase != null) { 
      myDataBase.close(); 
     } 
     super.close(); 
    } 

} 
+4

내 코드가 무엇이 잘못되었는지 알아야합니다. –

0

처럼 작동하고 난 정말이 문제에 좋은 방법입니다 생각하지 않습니다. SQLiteOpenHelper 그런 식으로 사용되는 것은 아닙니다. 헬퍼 클래스 외부에서 DB를 복사 한 다음 getReadableDatabase 및 getWritableDatabase를 통해 SQLiteDatabase를 가져 오는 데 도움이되는 도우미를 초기화해야합니다.

그러나 코드를 읽으면 createDataBase 함수에서 copyDataBase 전에 getReadableDatabase를 호출하는 이유가 표시되지 않습니다. 또한 hotveryspicy에서 제시하는대로 데이터베이스 경로를 확인해야합니다.

예외의 스택 추적을 게시 할 수 있습니까?

이 편집을 시도

:

public class ExternalDbOpenHelper extends SQLiteOpenHelper { 

public static String DB_PATH; 
public static String DB_NAME; 
public SQLiteDatabase database; 
public final Context context; 

public SQLiteDatabase getDb() { 
    return database; 
} 

public ExternalDbOpenHelper(Context context, String databaseName) { 
    super(context, databaseName, null, 1); 
    this.context = context; 

    String packageName = context.getPackageName(); 
    DB_PATH = String.format("%s//data//%s//databases//", Environment.getDataDirectory(), packageName); // as per hotveryspicy comment 
    DB_NAME = databaseName; 
    openDataBase(); 
} 

public void createDataBase() { 
    boolean dbExist = checkDataBase(); 
    if (!dbExist) { 
     //this.getReadableDatabase(); why do you call getReadableDatabase() here? 
     try { 
      copyDataBase(); 
     } catch (IOException e) { 
      // Log.e(this.getClass().toString(), "Copying error"); 
      //throw new Error("Error copying database!"); 
     } 
    } else { 
     // Log.i(this.getClass().toString(), "Database already exists"); 
    } 
} 

private boolean checkDataBase() { 
    SQLiteDatabase checkDb = null; 
    try { 
     String path = DB_PATH + DB_NAME; 
     checkDb = SQLiteDatabase.openDatabase(path, null, 
       SQLiteDatabase.OPEN_READONLY); 
    } catch (SQLException e) { 
     // Log.e(this.getClass().toString(), "Error while checking db"); 
    } 

    if (checkDb != null) { 
     checkDb.close(); 
    } 
    return checkDb != null; 
} 

private void copyDataBase() throws IOException { 

    InputStream externalDbStream = context.getAssets().open(DB_NAME); 

    String outFileName = DB_PATH + DB_NAME; 

    OutputStream localDbStream = new FileOutputStream(outFileName); 

    byte[] buffer = new byte[1024]; 
    int bytesRead; 
    while ((bytesRead = externalDbStream.read(buffer)) > 0) { 
     localDbStream.write(buffer, 0, bytesRead); 
    } 

    localDbStream.close(); 
    externalDbStream.close(); 

} 

public SQLiteDatabase openDataBase() throws SQLException { 
    String path = DB_PATH + DB_NAME; 
    if (database == null) { 
     createDataBase(); 
     //database = SQLiteDatabase.openDatabase(path, null, 
       //SQLiteDatabase.OPEN_READWRITE); 

     database = getWritableDatabase(); // <- try with this   
    } 
    return database; 
} 

@Override 
public synchronized void close() { 
    if (database != null) { 
     database.close(); 
    } 
    super.close(); 
} 

@Override 
public void onCreate(SQLiteDatabase db) { 
} 

@Override 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
} 
} 
+0

스택 추적을 게시했습니다. –

+0

데이터베이스를 찾지 못하는 것 같습니다. 코드 편집에 대한 편집을 테스트 했습니까? –

+0

예. 설치 후 처음으로 응용 프로그램이 다운되거나 응용 프로그램 설정에서 '데이터 지우기'가 발생하면 –

관련 문제