Доступ к определенной загруженной базе данных .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()
и все работает. Карта загружается.
Большое спасибо за вашу помощь!