SD卡中的Android SQLite DB

时间:2012-09-02 11:01:14

标签: android sqlite android-sdcard

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

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

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

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

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


修改1 我的DB Helper Class

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

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

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

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

1 个答案:

答案 0 :(得分:1)

你能提供一些代码吗?

  

我通过修改我们通常使用的DatabaseHelper类

来做到这一点

您能描述一下您做了哪些修改? 如果您正在使用SQLiteOpenHelper,请注意传递给它的构造函数的DB路径是相对于/ data / data / package / databases /文件夹的,因此您无法在那里传递SD路径。如果您仍然需要这个 - 我建议您使用ContextWrapper并重新定义它的getDatabasePath方法以指向您的SD数据库。