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

M.S*_*.S. 17 sqlite android android-sqlite

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

使用DownloadManager,我从我们的网络服务器下载一个sqlite数据库文件(像.mbtiles这样的结构),它包含地图图块图像的blob("离线地图")并通过它存储在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);
}
Run Code Online (Sandbox Code Playgroud)

下载似乎工作得很好. 我注册了一个BroadcastReceiver接收DownloadManager.ACTION_DOWNLOAD_COMPLETE并存储"map.sqlite"的路径使用SharedPreferences.

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

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);
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

我的问题是,我似乎以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
Run Code Online (Sandbox Code Playgroud)

[...]

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

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

我知道这里至少存在三个与上述错误消息非常相似的问题,但它们并不具体,详细和/或不完全符合我的需要.阅读本文后,我也无法解决问题:

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

非常感谢您的帮助!


更新:

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

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

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

M.S*_*.S. 4

我终于找到了这个错误,这是一个非常发人深省的错误。

我收到了URIDownloadManager.ACTION_DOWNLOAD_COMPLETE,并将其存储到下载的数据库中,以供以后在方法内参考:SharedPreferencesshouldInterceptRequest

...
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();
Run Code Online (Sandbox Code Playgroud)

shouldInterceptRequest然后我打电话给

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

从而将URI传递给openDatabase,而不仅仅是Path

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

非常感谢您的帮助!