【问题标题】:open a sqlite database when choosing folder with ACTION_OPEN_DOCUMENT_TREE选择带有 ACTION_OPEN_DOCUMENT_TREE 的文件夹时打开一个 sqlite 数据库
【发布时间】:2015-04-21 14:25:41
【问题描述】:

我在文件夹 /sdcard/myfolder/db/mydb.db 中有一个现有的 sqlite 数据库。 我的应用显示了一个选择文件夹的对话框:

Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
                      startActivityForResult(intent, 42);

弹出对话框,我可以选择文件夹:

我选择文件夹 /sdcard/myfolder/db/ 并按选择/确定。

我的 onActivityResult 被调用。我浏览所有文件,如果文件是我的“mydb.db”,那么我尝试使用 SQLiteDatabase.openDatabase(); 打开 sqlite 数据库;我得到一个错误(见下文)

我对问题的猜测: 这将不起作用,因为 openDatabase 需要像 /sdcard/myfolder/db/mydb.db 这样的数据库的完整路径

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // if (requestCode == REQUEST_QUICKLIST) {
        if (resultCode == Activity.RESULT_OK) {
            if(requestCode==42){
                // TreeDialog for choosing the Installdirectory
                Uri treeUri = data.getData();
                DocumentFile pickedDir = DocumentFile.fromTreeUri(this, treeUri);
                for (DocumentFile file : pickedDir.listFiles()) {
                    if(file.getName().equals("mydb.db")){
                        SQLiteDatabase sqliteTest=  SQLiteDatabase.openDatabase(file.getUri().getPath(), null, SQLiteDatabase.OPEN_READONLY);   
                    }
                    Log.d("DEBUG FILE", "Found file " + file.getName() + " with size " + file.length() + " " + file.getParentFile().getName());
                }

file.getUri().getPath() 的值为:/tree/primary:myfolder/db/document/primary:myfolder/db/mydb.db

如何打开sqlite数据库?

堆栈跟踪:

 java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=42, result=-1, data=Intent { dat=content://com.android.externalstorage.documents/tree/primary:myfolder/db flg=0xc3 }} to activity {mycompany.browser/mycompany.browser.browser}: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
    at android.app.ActivityThread.deliverResults(ActivityThread.java:3976)
    at android.app.ActivityThread.handleSendResult(ActivityThread.java:4019)
    at android.app.ActivityThread.access$1400(ActivityThread.java:172)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1471)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:145)
    at android.app.ActivityThread.main(ActivityThread.java:5834)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)
    Caused by: android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
    at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:318)
    at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:228)
    at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:512)
    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:206)
    at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:178)
    at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:891)
    at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:861)
    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
    at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:671)
    at mycompany.browser.browser.onActivityResult(browser.java:1533)
    at android.app.Activity.dispatchActivityResult(Activity.java:6475)
    at android.app.ActivityThread.deliverResults(ActivityThread.java:3972)

【问题讨论】:

  • Android DocumentFile 不是java.io.File 的子类或代表的本机文件系统文件,但它可能(或可能不)包装一个。查看 file.isFile() 是否返回 true。如果没有(如果它使用更间接的共享机制),您可能无法将其作为数据库打开,除非您的数据库引擎已扩展为支持 DocumentFile 而不是文字文件系统文件。鉴于尝试在失败之前进入本机代码(来自 SQlite 项目,而不是来自 Android),它看起来不太可能支持。
  • 嗨,克里斯。谢谢。所以你的答案是:“不,这是不可能的”。我不希望,也希望其他专家对此有任何提示,否则这个框架不适用于这种情况。其他专家可以确认或有其他解决方案吗?我当然知道它不是 java.io.File 的子类,但我想一定有办法实现这一点。
  • 严格来说,我并不是说这是不可能的,而是只有在以下情况下才有可能:1)您的 DocumentFile 包装了一个文件或 2)您的数据库引擎已扩展为支持 DocumentFile 引用.第一个你可以检查,而第二个我在 Android 源代码中看不到任何明显的东西。
  • 克里斯,请让其他专家也发表声明,以免像上次那样无休止的聊天,问题不再有吸引力。对不起这句话,但我不知道该怎么说。如果你有具体的解决方案,在这里给出,否则我猜你看看别人的想法也会很有趣。
  • “最后一次”的问题在于,您显然想要回答一个与您在帖子中实际提出的问题截然不同的问题。

标签: android sqlite android-intent android-5.0-lollipop


【解决方案1】:

我没有测试,因为 Lollipop 设备目前不可用,但这应该可以工作,如果有任何问题,请告诉我!

if(file.getName().equals("mydb.db")){
    Uri uri = file.getUri();
    Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri,
                      DocumentsContract.getTreeDocumentId(uri));
    String path = ASFUriHelper.getPath(this, docUri);
    SQLiteDatabase sqliteTest=  SQLiteDatabase.openDatabase(path, null, 
                                     SQLiteDatabase.OPEN_READONLY);
}

ASFUriHelper.getPath() 方法和中间方法的要点可以在这里找到:ASFUriHelper.getPath()

【讨论】:

  • 我用棒棒糖在 2 个不同的设备上进行了测试。非常感谢!
  • 此代码不适用于外部 SD 卡。如果我选择一个外部 SD 卡的文件夹,ASFUriHelper 返回 null。
【解决方案2】:

感谢您的回答。对我来说,问题是当我在 SD 卡上选择目录时,getPath 在我的 HTC M8 和 SD 卡上返回 NULL。

这是因为 uri 在 getpath 的代码中不包含“primary”作为 espectect :

if ("primary".equalsIgnoreCase(type)) {
    return Environment.getExternalStorageDirectory() + "/" + split[1];
}

对我来说,类型包含“1AF0-170C”,完整的 uri 是:

/tree/1AF0-170C:SmartDiveBook/document/1AF0-170C:SmartDiveBook/SmartDiveBook.db 

【讨论】:

  • 能否请您添加更多源代码以更好地理解它?
猜你喜欢
  • 2011-05-24
  • 1970-01-01
  • 2014-11-11
  • 2014-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-02
  • 2020-05-11
相关资源
最近更新 更多