Доступ к определенной загруженной базе данных .sqlite во внешнем хранилище из приложения для Android

Я пытаюсь реализовать функцию автономной карты в приложении на базе Android для Android:

С помощью DownloadManager, я загружаю файл базы данных sqlite (такой структуры, как .mbtiles), с нашего веб-сервера, который содержит капли изображений на карте ( "офлайн-карта" ) и сохраняет он находится в внешнем хранилище 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 и сохраняю путь к map.sqlite с помощью SharedPreferences.

Чтобы получить доступ к базе данных из 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.

Вопрос: Почему мой код не работает; как я могу заставить его работать?

Я знаю, что здесь есть, по крайней мере, три очень похожих вопроса с приведенным выше сообщением об ошибке, но они не являются такими специфическими, подробными и/или не соответствуют моим потребностям. Я также не смог решить проблему после прочтения этой статьи:

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

Большое спасибо за вашу помощь!


UPDATE:

Я попытался создать новую базу данных, используя SQLiteDatabase.openOrCreateDatabase() во внешнем хранилище, чтобы сравнить ее с исходной базой данных. Он не был создан - вместо этого я неожиданно столкнулся с тем же сообщением об ошибке (не смог открыть базу данных).

Затем я снова попытался открыть новую базу данных, на этот раз в ОЗУ, используя SQLiteDatabase.openOrCreateDatabase(":memory:", null), и она не выдала никакой ошибки.

Таким образом, я начинаю думать, что проблема заключается в ограничении доступа к внешнему хранилищу или ошибке при обращении к внешнему хранилищу, а не к самому файлу базы данных.

Ответы

Ответ 1

Наконец-то мне удалось найти ошибку, довольно отрезвляющую.

Я получил 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, а не только Path.

Теперь я Uri.parse(preferences.getString("map_uri", ...)).getPath() и все работает. Карта загружается.

Большое спасибо за вашу помощь!