解決
カスタム DBHelper クラスで getReadableDatabase() と getWritableDatabase() をオーバーライドする必要がありました。
私はユニークな種類の問題に直面しています。
これまで、電話のメモリ上で内部的に 1 つの SQLite DB を使用する Android アプリを作成してきましたが、完全に動作します。ここで、別の DB を追加し、それを SD カードに保存したいと考えました。これは、通常使用する DatabaseHelper クラスを変更することで実現しました。また、アセット フォルダから 1 つの DB の SD カードと別の DB の内部メモリ ロケーションに db を転送するスクリプトも作成しました。
今私が直面している問題は、外部 DB にアクセスしようとすると、Android が /data/data/package_name/databases フォルダーに内部 DB を作成するため、そのようなテーブル例外が発生しないことです。
なぜこのエラーが発生するのか誰か教えてください!
1 My DB ヘルパー クラスを編集
public class DBHelper extends SQLiteOpenHelper {
private Context myContext;
private String DB_PATH;
private String DB_NAME;
private boolean isExternal;
private SQLiteDatabase myDataBase;
private final String TAG = "ERROR";
public DBHelper(Context AppC, String DB_NAME, boolean isExternal,
int DB_VERSION) {
super(AppC, DB_NAME + ".sqlite", null, DB_VERSION);
this.myContext = AppC;
this.isExternal = isExternal;
this.DB_NAME = DB_NAME;
setDbPath();
}
private void setDbPath() {
if (this.isExternal) {
try {
DB_PATH = Environment.getExternalStorageDirectory()
+ "/myappname/";
} catch (Exception e) {
DB_PATH = "/mnt/sdcard/myappname/";
}
} else {
try {
DB_PATH = Environment.getDataDirectory()
+ "/data/my.app.package/databases/";
} catch (Exception e) {
DB_PATH = "data/data/my.app.package/databases/";
}
}
}
/**
* Creates a empty database on the system and rewrites it with your own
* database.
* */
public void createDataBase() throws IOException {
boolean dbExist = checkDataBase();
if (!dbExist) {
try {
copyDataBase();
} catch (Exception E) {
// MRC
}
}
}
/**
* Copies your database from your local assets-folder to the just created
* empty database in the system folder, from where it can be accessed and
* handled. This is done by transferring byte streams.
* */
private void copyDataBase() throws IOException {
String filePath = DB_PATH + this.DB_NAME + ".sqlite";
if (this.isExternal) {
File file = new File(filePath);
if (!file.exists()) {
File dir = new File(DB_PATH);
if (dir.exists() || dir.mkdirs()) {
transferFromAssets(this.DB_NAME + ".zip", filePath);
} else {
Log.d(TAG, "Unable to create dir " + DB_PATH);
}
}
} else {
// By calling this method and empty database will be created
// into the default system path of your application so we
// will be able to overwrite that database with our
// database.
SQLiteDatabase db_Read = this.getReadableDatabase();
db_Read.close();
transferFromAssets(this.DB_NAME + ".zip", filePath);
}
}
private void transferFromAssets(String from, String to) throws IOException {
ZipInputStream myInput = new ZipInputStream(myContext.getAssets().open(
from));
myInput.getNextEntry(); // Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(to);
// transfer bytes from the inputfile to the outputfile
AndroidUtil.copyStream(myInput, myOutput);
}
/**
* Check if the database already exist to avoid re-copying the file each
* time you open the application.
*
* @return true if it exists, false if it doesn't
*/
private boolean checkDataBase() {
File dbFile = new File(DB_PATH + this.DB_NAME + ".sqlite");
return dbFile.exists();
}
public void openDataBase() throws SQLException {
String myPath = DB_PATH + this.DB_NAME + ".sqlite";
Log.d(TAG, "Opening DB:" + myPath);
myDataBase = SQLiteDatabase.openDatabase(myPath, null,
SQLiteDatabase.OPEN_READWRITE);
}
@Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
*私の内部メモリ DB のクラスのコンストラクター *
public WordsDB(Context AppC) {
DBAPI = new DBHelper(AppC, "DB_NAME", false, 11);
this.AppC = AppC;
try {
DBAPI.createDataBase();
DBAPI.openDataBase();
} catch (IOException e) {
CustomToast.Toast(AppC, "", TCategory_E.CRITICAL_ERROR,
TDuration_E.LONG, TPosition_E.CENTER);
// MRC
}
}
** 外部 DB クラスのコンストラクター **
public BackupDB(Context AppC) {
DBAPI = new DBHelper(AppC, "/mnt/sdcard/myapp/backup-db",
true, 11);
this.AppC = AppC;
try {
DBAPI.createDataBase();
DBAPI.openDataBase();
} catch (IOException e) {
CustomToast.Toast(AppC, "", TCategory_E.CRITICAL_ERROR,
TDuration_E.LONG, TPosition_E.CENTER);
// MRC
}
}
編集 2
エラーにつながる外部 DB のヘルパー クラスの関数:
public void setValue(int No, int Stars) {
try {
ContentValues update = new ContentValues();
update.put(COL_STARRED, Stars);
String args[] = { No + "" };
SQLDB = DBAPI.getWritableDatabase();
SQLDB.acquireReference();
SQLDB.update(TABLE_NAME, update, COL_ID + "=?", args);
SQLDB.releaseReference();
SQLDB.close();
} catch (Exception E) {
Log.d(TAG, E.getMessage());
}
}
外部 DB を内部 DB として使用しようとすると、エラーが発生せず、外部 DB に対して何か問題があると思います。