M.S. M.S. - 1 month ago 17
Android Question

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

I am trying to implement an offline map feature in an android WebView-based app:

Using

DownloadManager
, I download an sqlite database file (of a structure like .mbtiles) from our webserver, which contains blobs of the map tile images (the "offline map") and store it in the android external storage through

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);
}


The Download seems to work perfectly well.
I register a
BroadcastReceiver
to receive
DownloadManager.ACTION_DOWNLOAD_COMPLETE
and store the path to "map.sqlite" using
SharedPreferences
.

To access the database from JavaScript for using the tile images in the
WebView
, I intercept XHRequests by checking for a custom fictive schema name
customhttp:
in the 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);
}
}
});


My problem is that I seem to implement
openDatabase()
in a wrong way
as I get the following unpleasant error with the corresponding line, but can't figure out why:

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


[...]

The file exists, is not corrupt and its path seems to be correct. I was able to open the file using an SQLite viewing app.

Question: Why does my Code not work; how can I make it work?

I am aware that there exist at least three very similar questions with the above error message here, but they are not that specific, detailed and/or do not exactly fit my needs. I also didn't manage to solve the problem after reading this article:

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

Thank you very much for your help!




UPDATE:

I tried creating a new database using
SQLiteDatabase.openOrCreateDatabase()
in external storage in order to compare it to the original database. It was not created - instead I surprisingly confronted the same error message (could not open database).

Then I tried again to open a new database, this time in RAM, using
SQLiteDatabase.openOrCreateDatabase(":memory:", null)
and it did not throw any error.

Thus I begin to think that the problem is some access restriction to external storage or a mistake when addressing external storage rather than the database file itself.

Answer

I finally managed to find the mistake, a quite sobering one.

I received DownloadManager.ACTION_DOWNLOAD_COMPLETE and stored the URI to the downloaded database in SharedPreferences for later reference inside the shouldInterceptRequest method using:

...
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();

In shouldInterceptRequest I then called

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

and thereby passed the URI to openDatabase, not the Path alone.

I now Uri.parse(preferences.getString("map_uri", ...)).getPath() and everything works. The map loads.

Thank you very much for your help!

Comments