在我的应用程序中,我使用..。
myFilesDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/Android/data/" + packageName + "/files");
myFilesDir.mkdirs();这很好,结果是.
/mnt/sdcard/Android/data/com.mycompany.myApp/files我需要一个SQLite DB,我想要存储在SD卡上,所以我扩展SQLiteOpenHelper如下.
public class myDbHelper extends SQLiteOpenHelper {
public myDbHelper(Context context, String name, CursorFactory factory, int version) {
// NOTE I prefix the full path of my files directory to 'name'
super(context, myFilesDir + "/" + name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
// Create tables and populate with default data...
}
}到目前为止,还好--我第一次调用getReadableDatabase()或getWriteableDatabase()时,在SD卡上创建了空DB,并由onCreate()填充它。
所以问题就在这里--这个应用程序正在测试中,可能有5到6个人,和我一样,他们运行的是Androidv2.2,一切都很好。不过,我有一个测试器,运行v2.1,当myDbHelper试图在第一次使用时创建DB时,它会崩溃,以下是.
E/AndroidRuntime( 3941): Caused by: java.lang.IllegalArgumentException: File /nand/Android/data/com.mycompany.myApp/files/myApp-DB.db3 contains a path separator
E/AndroidRuntime( 3941): at android.app.ApplicationContext.makeFilename(ApplicationContext.java:1445)
E/AndroidRuntime( 3941): at android.app.ApplicationContext.openOrCreateDatabase(ApplicationContext.java:473)
E/AndroidRuntime( 3941): at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:193)
E/AndroidRuntime( 3941): at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:98)
E/AndroidRuntime( 3941): at android.database.sqlite.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:158)文件目录的路径是一个奇怪的路径("/nand"),因为它是内部内存,虽然不是手机的内部内存,但它是getExternalStorageDirectory()为该设备返回的路径。
我能看到三个可能的答案..。
如果有上述任何或全部申请,如果有人能帮我解决这个问题,我将不胜感激。
谢谢。
发布于 2011-03-16 23:56:42
在历史上,您无法在SQLiteOpenHelper中使用路径。它只适用于简单的文件名。我没有意识到他们在Android2.2中放宽了这个限制。
如果您希望使用SD卡上的数据库,并且希望支持Android2.1及更早版本,则不能使用SQLiteOpenHelper。
抱歉的!
发布于 2012-02-06 23:37:12
如果您提供了一个SQLiteOpenHelper自定义 ContextClass,并且您在目标目录中有写访问权限,那么您可以使用自定义路径。
public class DatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 3;
.....
DatabaseHelper(final Context context, String databaseName) {
super(new DatabaseContext(context), databaseName, null, DATABASE_VERSION);
}
}下面是自定义的DatabaseContext类,它完成了所有的魔术:
class DatabaseContext extends ContextWrapper {
private static final String DEBUG_CONTEXT = "DatabaseContext";
public DatabaseContext(Context base) {
super(base);
}
@Override
public File getDatabasePath(String name) {
File sdcard = Environment.getExternalStorageDirectory();
String dbfile = sdcard.getAbsolutePath() + File.separator+ "databases" + File.separator + name;
if (!dbfile.endsWith(".db")) {
dbfile += ".db" ;
}
File result = new File(dbfile);
if (!result.getParentFile().exists()) {
result.getParentFile().mkdirs();
}
if (Log.isLoggable(DEBUG_CONTEXT, Log.WARN)) {
Log.w(DEBUG_CONTEXT, "getDatabasePath(" + name + ") = " + result.getAbsolutePath());
}
return result;
}
/* this version is called for android devices >= api-11. thank to @damccull for fixing this. */
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
return openOrCreateDatabase(name,mode, factory);
}
/* this version is called for android devices < api-11 */
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
// SQLiteDatabase result = super.openOrCreateDatabase(name, mode, factory);
if (Log.isLoggable(DEBUG_CONTEXT, Log.WARN)) {
Log.w(DEBUG_CONTEXT, "openOrCreateDatabase(" + name + ",,) = " + result.getPath());
}
return result;
}
}更新2012年6月:
这是如何运作的(@barry问题):
普通的android应用程序都有相对于应用文件夹的本地数据库文件。通过使用覆盖getDatabasePath()的客户上下文,数据库现在相对于sd卡上的另一个目录。
更新2015年2月:
在用新的Androd-4.4设备替换了我的旧Androd-2.2设备之后,我发现我的解决方案已经失效了。多亏了@damccull的回答,我才能解决这个问题。我已经更新了这个答案,所以这应该是一个工作的例子。
2017年5月更新:
统计:在200多个github项目中使用此方法
发布于 2013-06-23 06:43:02
K3b的答案太棒了。让我开始工作了。但是,在使用API级别11或更高版本的设备上,您可能会看到它停止工作。这是因为添加了openOrCreateDatabase()方法的新版本。它现在包含以下签名:
openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags, DatabaseErrorHandler errorHandler)这似乎是默认情况下在某些具有此方法的设备上调用的方法。
为了使此方法在这些设备上工作,您需要进行以下更改:
首先,编辑现有的方法,使其只返回调用新方法的结果。
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode,
CursorFactory factory) {
return openOrCreateDatabase(name, mode, factory, null);
}其次,使用以下代码添加新的覆盖。
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name).getAbsolutePath(),null,errorHandler);
return result;
}这段代码与k3b的代码非常相似,但请注意,SQLiteDatabase.openOrCreateDatabase使用的是字符串而不是文件,我使用了允许DatabaseErrorHandler对象的版本。
https://stackoverflow.com/questions/5332328
复制相似问题