Accesso a un determinato database .sqlite scaricato in una memoria esterna da un’app Android

Sto cercando di implementare una funzione di mappa offline in un’app Android basata su WebView:

Usando DownloadManager , ho scaricato un file di database sqlite (di una struttura come .mbtiles) dal nostro server web , che contiene blob delle immagini della mappa della mappa (la “mappa offline”) e lo memorizziamo nell’archivio esterno di Android tramite

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

Il download sembra funzionare perfettamente. Registrazione un BroadcastReceiver per ricevere DownloadManager.ACTION_DOWNLOAD_COMPLETE e memorizzare il percorso su “map.sqlite” usando SharedPreferences .

Per accedere al database da JavaScript per l’utilizzo delle immagini delle tessere in WebView , intercetto XHRequests controllando il nome di uno schema fittizio personalizzato customhttp: nell’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); } } }); 

Il mio problema è che mi sembra di implementare openDatabase() in modo errato in quanto ottengo il seguente spiacevole errore con la riga corrispondente, ma non riesco a capire perché:

 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 

[…]

Il file esiste, non è corrotto e il suo percorso sembra essere corretto. Sono stato in grado di aprire il file utilizzando un’app di visualizzazione SQLite.

Domanda: perché il mio codice non funziona; come posso farlo funzionare?

Sono consapevole che esistono almeno tre domande molto simili con il precedente messaggio di errore qui, ma non sono specifiche, dettagliate e / o non corrispondono esattamente alle mie esigenze. Anche io non sono riuscito a risolvere il problema dopo aver letto questo articolo:

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

Grazie mille per il tuo aiuto!


AGGIORNARE:

Ho provato a creare un nuovo database utilizzando SQLiteDatabase.openOrCreateDatabase() nella memoria esterna per poterlo confrontare con il database originale. Non è stato creato – invece ho sorprendentemente affrontato lo stesso messaggio di errore (non ho potuto aprire il database).

Poi ho provato di nuovo ad aprire un nuovo database, questa volta nella RAM, usando SQLiteDatabase.openOrCreateDatabase(":memory:", null) e non ha generato alcun errore.

Così comincio a pensare che il problema sia una qualche restrizione di accesso allo storage esterno o un errore quando si indirizza allo storage esterno piuttosto che al file di database stesso.

Finalmente riuscii a trovare l’errore, piuttosto deludente.

Ho ricevuto DownloadManager.ACTION_DOWNLOAD_COMPLETE e ho memorizzato l’ URI nel database scaricato in SharedPreferences per un successivo riferimento all’interno del metodo shouldInterceptRequest utilizzando:

 ... 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 ho quindi chiamato

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

e quindi ha passato l’ URI a openDatabase , non al solo Path .

Io ora Uri.parse(preferences.getString("map_uri", ...)).getPath() e tutto funziona. La mappa viene caricata.

Grazie mille per il tuo aiuto!