0

解决方案

我必须在我的自定义 DBHelper 类中覆盖 getReadableDatabase() 和 getWritableDatabase()。

我面临着一种独特的问题。

到目前为止,我编写的 Android 应用程序在手机内存内部使用了一个 SQLite DB,并且运行良好。现在我想添加另一个数据库并将其存储在 SD 卡上。我通过修改我们通常使用的 DatabaseHelper 类来做到这一点。我还编写了一个脚本,将 db 从 assets 文件夹传输到 SD 卡用于一个 DB,并将内部存储器位置用于另一个。

现在我面临的问题是,当我尝试访问外部数据库时,android 在 /data/data/package_name/databases 文件夹中创建了一个内部数据库,因此我最终没有得到这样的表异常

有人可以告诉我为什么会收到此错误!


编辑 1 我的数据库助手类

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) {

}

}

*我的内存数据库类的构造函数 *

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
    }
}

** 我的外部数据库类的构造函数 **

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

导致错误的外部数据库助手类中的函数:

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());
    }
}

如果我尝试将外部数据库用作内部数据库,则没有错误导致我认为我为外部数据库做错了什么。

4

1 回答 1

1

你能提供一些代码吗?

我通过修改我们通常使用的 DatabaseHelper 类来做到这一点

Can you please describe what modification did you made? If you are using SQLiteOpenHelper, be aware that DB path, that is passed to it's constructor - is relative to /data/data/package/databases/ folder, so you cannot pass SD path there. If you will still need this - I'll suggest using ContextWrapper and redefining it's getDatabasePath method to point to your SD DB.

于 2012-09-02T11:19:16.067 回答