2013-12-17 6 views
14

Ho un widget con nove immagini di sfondo. L'immagine è stata salvata in/sdcard/mydir/bgs.Android - Impossibile aprire il contenuto: file: /// memoria/emulato/0

Quando provo a caricare un'immagine con il metodo setImageViewUri, ho questo errore:

Unable to open content: file:///storage/emulated/0/sdcard/mydir/bgs 

..

poi

...

open failed: EACCES (Permission denied) 

Questo appare solo sulla schermata iniziale e solo con Nexus 10 e Nexus 7 (con l'ultimo launcher 4.4 questo bug no esistere). Ho anche alcune RemoteViews sulla mia applicazione e tutto funziona correttamente.

Ho anche aggiunto in manifest READ_EXTERNAL_STORAGE, o WRITE_EXTERNAL_STORAGE.

Come posso risolvere?

AGGIORNAMENTO: Ho ispezionato il metodo setImageViewUri e ho scoperto che cambia il percorso del mio file.

if (value != null) { 
      // Resolve any filesystem path before sending remotely 
      value = value.getCanonicalUri(); 
      if (StrictMode.vmFileUriExposureEnabled()) { 
       value.checkFileUriExposed("RemoteViews.setUri()"); 
      } 
     } 

Questo metodo ricevere il mio valore (/ sdcard/mydir/BGS) e lo cambia in (stoccaggio/emulato/0/sdcard/mydir/BGS). Ma questo file non esiste nel sistema tramite adb.

+0

Condividi il tuo codice e anche pubblicare il tuo piena potenza logcat. –

risposta

6

Sembra setImageViewUri è più sicuro da usare con il file: // URI.

Perché?

Jellybean ha introdotto l'autorizzazione READ_EXTERNAL_STORAGE. Le app che vogliono leggere da una memoria esterna devono possedere questa autorizzazione. Questo non è stato applicato di default fino a KitKat.

Il programma di avvio non è autorizzato. In effetti, non è garantito che qualsiasi RemoteView che si collega detenga tale autorizzazione. Questo rende pericoloso usare setImageViewUri, dato che non si sa se la vista dell'immagine remota sarà in grado di leggere l'uri dato.

Che ora?

Opzione 1: utilizzare setImageViewBitmap.

Potrebbe essere stata spostata da questa opzione a causa di transazioni di raccoglitore fallite. Il trucco per questi è solo assicurarsi che l'immagine sia inferiore a 1 MB. Non è così difficile come sembra. Puoi calcolare esattamente quanto sarà grande la tua immagine. Ad esempio se stai utilizzando un'immagine ARGB_8888 significa che avrai bisogno di 4 byte per pixel.Possiamo Calulate la dimensione massima da:

1 Mb = 1048576 bytes = 262144 pixels = 512 x 512 image

Naturalmente si può spremere più fuori di esso utilizzando RGB_565 per ottenere 2x i pixel.

Inoltre, potresti non aver bisogno di un'immagine enorme se il tuo widget è piccolo. Il tuo AppWidget e domanda sulle opzioni specifiche dal seguente:

Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetIds[i]); 

int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH); 
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT); 

int maxWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH); 
int maxHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT); 

Basta essere consapevoli che i valori restituiti sono in tuffo, non pixel quindi sarà necessario convertire loro di scalare il bitmap.

Opzione 2: utilizzare un fornitore di contenuti

Se per qualche motivo ancora non ti piace la restrizione IPC, si può sempre costruire un fornitore di contenuti personalizzati. Passa quel uri nel setImageViewUri, e dovresti essere a posto.

E l'interruttore di percorso?

L'opzione di percorso non è il vero problema. Sembra che sia un problema, ma l'emulazione funziona davvero bene. Prova a creare un file all'interno di //storage/emulated/0/sdcard/mydir/bgs e il file verrà creato correttamente.

Si noterà che mentre l'eccezione è FileNotFoundException, il messaggio è Autorizzazione negata.

10

È necessario

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 

nel vostro manifesto.

+1

L'ho aggiunto. O LEGGI e SCRIVI l'autorizzazione. – CeccoCQ

0

Penso che stai inserendo il percorso della scheda SD manualmente. Invece di inserire manualmente il percorso scheda SD si dovrebbe ottenere il percorso di archiviazione in questo modo:

File extStore = Environment.getExternalStorageDirectory(); 
String mPath = extStore.getAbsolutePath() + "/mydir/bgs"; 
+0

Controlla la mia ultima modifica. Grazie. – CeccoCQ

14

Come da Lollipop, Google ha introdotto un nuovo modo di dare esplicitamente alle app il permesso che si desidera vengano utilizzate sul dispositivo e disabilitare quelle che si desidera negare all'app. Se notate, nel monitor android, il registro mostra

java.io.FileNotFoundException: /storage/emulated/0/advert.mp4: open failed: EACCES (Permission denied) 

EACCESS permission denied è la causa del famigerato FileNotFoundException del Java.

Per risolvere questo problema, basta goto vostro permesso App e consentire una conservazione per la vostra applicazione

enter image description here

+0

Quindi, per impostazione predefinita, tutte le autorizzazioni sono disabilitate ??! L'utente deve abilitare tutto ogni volta che si installa un'app? Non l'ho mai fatto sul mio telefono (versione 6.0.1) ... – Matt

+0

Si prega di non farlo su un'app rilasciata. I tuoi utenti non ti ringrazieranno. Dovresti invece richiedere l'autorizzazione in fase di runtime dalla tua app. https://developer.android.com/training/permissions/requesting.html – Kuffs