在我的应用程序中,我使用...
myFilesDir = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/Android/data/" + packageName + "/files");
myFilesDir.mkdirs();
Run Code Online (Sandbox Code Playgroud)
这很好,结果路径是......
/mnt/sdcard/Android/data/com.mycompany.myApp/files
Run Code Online (Sandbox Code Playgroud)
我需要一个我想要存储在SD卡上的SQLite DB,所以我将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...
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止一切顺利 - 我第一次打电话getReadableDatabase()
或getWriteableDatabase()
在SD卡上创建空DB并onCreate()
填充它.
所以这就是问题 - 该应用程序正在进行beta测试,可能有5或6个人,和我一样,他们运行的是Android v2.2,一切正常.我有一个测试人员,但是,运行v2.1并且myDbHelper
在第一次使用时尝试创建数据库时,它崩溃了以下...
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)
Run Code Online (Sandbox Code Playgroud)
文件目录的路径是奇数("/ nand"),因为它的内部存储器虽然不是电话自己的内部存储器 - 但它是getExternalStorageDirectory()
该设备返回的路径.
我可以看到三个可能的答案......
如果上述任何一项或全部适用,我会很感激,如果有人可以帮我解决这个问题.
谢谢.
k3b*_*k3b 40
如果提供自定义ContextClass并且在目标目录中具有写访问权限,则可以将SQLiteOpenHelper与自定义路径一起使用.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
这是自定义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;
}
}
Run Code Online (Sandbox Code Playgroud)
2012年6月更新:
这是如何工作的(@barry问题):
普通的Android应用程序拥有相对于app文件夹的本地数据库文件.通过使用覆盖getDatabasePath()
数据库的客户上下文,现在相对于SD卡上的不同目录.
更新2015年2月:
用新的android-4.4设备替换旧的android-2.2设备后,我发现我的解决方案不再适用了.感谢@ damccull的答案,我能够解决它.我已经更新了这个答案,所以这应该是一个有效的例子.
2017年更新:
统计:这个方法用于200多个github项目
Com*_*are 14
从历史上看,您无法使用路径SQLiteOpenHelper
.它只适用于简单的文件名.我没有意识到他们在Android 2.2中放宽了这个限制.
如果您希望在SD卡上使用数据库,并且希望支持Android 2.1及更早版本,则无法使用SQLiteOpenHelper
.
抱歉!
k3b的答案很棒.它让我工作.但是,在使用API级别11或更高级别的设备上,您可能会看到它停止工作.这是因为添加了新版本的openOrCreateDatabase()方法.它现在包含以下签名:
openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags, DatabaseErrorHandler errorHandler)
Run Code Online (Sandbox Code Playgroud)
这似乎是默认情况下在某些设备上使用此方法调用的方法.
为了使此方法适用于这些设备,您需要进行以下更改:
首先,编辑现有方法,使其只返回对新方法的调用结果.
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode,
CursorFactory factory) {
return openOrCreateDatabase(name, mode, factory, null);
}
Run Code Online (Sandbox Code Playgroud)
其次,使用以下代码添加新覆盖.
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory, DatabaseErrorHandler errorHandler) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name).getAbsolutePath(),null,errorHandler);
return result;
}
Run Code Online (Sandbox Code Playgroud)
此代码与k3b的代码非常相似,但请注意,SQLiteDatabase.openOrCreateDatabase采用String而不是File,并且我使用了允许DatabaseErrorHandler对象的版本.
归档时间: |
|
查看次数: |
18800 次 |
最近记录: |