从 android 应用程序访问外部存储中的某个下载的 .sqlite 数据库

Accessing a certain downloaded .sqlite database in external storage from an android app

我正在尝试在 android 基于 WebView 的应用程序中实现离线地图功能:

使用 DownloadManager我从我们的网络服务器下载了一个 sqlite 数据库文件(类似 .mbtiles 的结构),其中包含地图图块图像的 blob("offline map")并将其存储在 android 外部存储器中

public void downloadMap() {
    downloadManager = (DownloadManager) getActivity().getSystemService(Activity.DOWNLOAD_SERVICE);
    DownloadManager.Request r = new DownloadManager.Request(Uri.parse("http://sry.youtoknow.idontwant/map.sqlite"));

    r.setDestinationInExternalFilesDir(getContext(), "map", "map.sqlite");

    downloadManager.enqueue(r);
}

下载似乎运行良好。 我注册了一个 BroadcastReceiver 来接收 DownloadManager.ACTION_DOWNLOAD_COMPLETE 并使用 SharedPreferences.

存储到 "map.sqlite" 的路径

要从 JavaScript 访问数据库以使用 WebView 中的图块图像, 我通过检查自定义虚构架构名称来拦截 XHRequests customhttp: 在 URL:

webView.setWebViewClient(new WebViewClient() {
    public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
        String url = request.getUrl().toString();
        if (!url.startsWith("customhttp:")) {
            return null;
        } else {
            SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
            SQLiteDatabase db = SQLiteDatabase.openDatabase(preferences.getString("map_uri", Environment.getExternalStorageDirectory().getPath() + "berlin.sqlite"), null, SQLiteDatabase.OPEN_READONLY);
        }
    }
});

我的问题是我似乎以错误的方式实现了 openDatabase(),因为我在相应的行中遇到了以下令人不快的错误,但无法弄清楚为什么:

E/SQLiteLog(#####):      (14) cannot open file at line ##### of [##########]
E/SQLiteLog(#####):      (14) os_unix.c:#####: (2) open(//file:///storage/emulated/0/Android/data/idontwant.youtoknow.sry/files/map/map.sqlite) - 
E/SQLiteDatabase(#####): Failed to open database 'file:///storage/emulated/0/Android/data/idontwant.youtoknow.sry/files/map/map.sqlite'.
E/SQLiteDatabase(#####): android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database

[...]

文件存在,没有损坏,它的路径似乎是正确的。我能够使用 SQLite 查看应用程序打开文件。

问题:为什么我的代码不起作用;我怎样才能让它发挥作用?

我知道这里至少存在三个与上述错误消息非常相似的问题,但它们不是那么具体,详细 and/or 不完全符合我的需要。看了这篇文章我也没有解决问题:

http://blog.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/.

非常感谢您的帮助!


更新:

我尝试在外部存储中使用 SQLiteDatabase.openOrCreateDatabase() 创建一个新数据库,以便将其与原始数据库进行比较。它没有创建 - 相反,我出乎意料地遇到了相同的错误消息(无法 open 数据库)。

然后我再次尝试打开一个新数据库,这次是在 RAM 中,使用 SQLiteDatabase.openOrCreateDatabase(":memory:", null) 并且没有抛出任何错误。

因此我开始认为问题是对外部存储的某些访问限制或在寻址外部存储而不是数据库文件本身时出现错误。

终于找到错误了,挺清醒的。

我收到了DownloadManager.ACTION_DOWNLOAD_COMPLETE,把URI存到SharedPreferences下载的数据库里面,供以后参考shouldInterceptRequest 方法使用:

...
Cursor c = downloadManager.query(query);
if (c.moveToFirst()) {
    if (c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS)) == DownloadManager.STATUS_SUCCESSFUL) {
        Editor editor = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
        editor.putString("map_uri", c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)));
        editor.commit();
    }
}
c.close();

shouldInterceptRequest然后我打电话给

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
SQLiteDatabase db = SQLiteDatabase.openDatabase(preferences.getString("map_uri", Environment.getExternalStorageDirectory().getPath() + "map.sqlite"), null, SQLiteDatabase.OPEN_READONLY);

,从而将 URI 传递给 openDatabase,而不是 路径一个人。

我现在 Uri.parse(preferences.getString("map_uri", ...)).getPath() 一切正常。地图加载。

非常感谢您的帮助!