2012-12-13 20 views
7

Ho un'applicazione in cui è impostato un ImageView e può essere cliccato per essere aperto nella galleria.Condivisione di immagini archiviate nella memoria interna

Per impostazione predefinita, io uso il seguente codice per ottenere una directory di file dalla memoria esterna per memorizzare i miei file JPEG:

File picsDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"MyCameraApp"); 

Ma! Supponiamo che la memoria esterna non sia montata o semplicemente non esista (Galaxy Nexus), questo non funziona. Così ho scritto un'istruzione if attorno ad esso e ho ottenuto la directory cache interna come una caduta.

String state = Environment.getExternalStorageState() 
if(Environment.MEDIA_MOUNTED.equals(state)){ 
    File picsDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"MyCameraApp");  
}else{ 
    context.getCacheDir(); 
} 

Le immagini vengono visualizzate correttamente nell'ImageView, ma non vengono visualizzate quando il mio intento viene avviato.

Intent intent = new Intent();    
intent.setAction(android.content.Intent.ACTION_VIEW); 
intent.setDataAndType(Uri.fromFile(imgFile), "image/jpeg"); 
startActivity(intent); 

La galleria viene caricata, ma mostra una schermata nera. Presumibilmente perché la galleria non ha accesso ai file nella directory cache della mia app.

In alternativa, ho provato ad utilizzare il provider di contenuto multimediale che utilizza MediaStore.Images.Media.INTERNAL_CONTENT_URI, ma questo porta ad un errore quando si cerca di inser l'immagine:

java.lang.UnsupportedOperationException: Writing to internal storage is not supported. 

Cosa devo fare?

+0

Forse ho potuto provare il confezionamento del bitmap con l'intento? Come 'intent.putExtra (" BitmapImage ", bitmap);'. Le mie immagini sono in genere di circa 5 MB. – Maarten

+0

Puoi archiviare le immagini nella memoria privata dell'applicazione e concedere l'accesso generale a LEGGERE SOLO a queste, tuttavia molte applicazioni tra cui alcuni dei built-in di google non si preoccuperanno di controllare se possono accedervi quando gli viene consegnato un percorso, ma semplicemente Supponiamo che non possano e non riescano, anche quando l'applicazione proprietaria ha effettivamente concesso l'accesso globale in lettura. –

risposta

3

Suppongo che il problema qui è che si sta tentando aperto con la galleria un file salvato in uno spazio privato della memoria (getCacheDir restituire un percorso relativo alla vostra applicazione e solo l'applicazione può accedere a tale percorso di memoria)

Se non è possibile salvare nella memoria esterna, è possibile provare a salvare in un percorso pubblico (ma in questo modo i file multimediali possono essere manipolati da ogni app e se si disinstalla l'applicazione non pulisce i supporti generati che sono stati salvati lì)

Se si desidera utilizzare la memoria interna privata, è possibile scrivere il ContentProvider

modifica per pubblicare un fornitore di contenuti che utilizzo per capire cosa ho detto. questo è il mio fornitore di contenuti (ho appena postato la parte rilevante è necessario):

public class MediaContentProvider extends ContentProvider { 
private static final String TAG = "MediaContentProvider"; 

// name for the provider class 
public static final String AUTHORITY = "com.way.srl.HandyWay.contentproviders.media"; 

private MediaData _mediaData; 

// UriMatcher used to match against incoming requests 
private UriMatcher _uriMatcher; 

@Override 
public int delete(Uri uri, String selection, String[] selectionArgs) { 
    // TODO Auto-generated method stub 
    return 0; 
} 

@Override 
public String getType(Uri uri) { 
    // TODO Auto-generated method stub 
    return null; 
} 

@Override 
public Uri insert(Uri uri, ContentValues values) { 
    // TODO Auto-generated method stub 
    return null; 
} 

@Override 
public boolean onCreate() { 
    uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 

    // Add a URI to the matcher which will match against the form 
    // 'content://com.stephendnicholas.gmailattach.provider/*' 
    // and return 1 in the case that the incoming Uri matches this pattern 
    _uriMatcher.addURI(AUTHORITY, "*", 1); 

    return true; 
} 

@Override 
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 
    // TODO Auto-generated method stub 
    return null; 
} 

@Override 
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 
    // TODO Auto-generated method stub 
    return 0; 
} 

@Override 
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 

    Log.v(TAG, "Called with uri: '" + uri + "'." + uri.getLastPathSegment()); 

    // Check incoming Uri against the matcher 
    switch (_uriMatcher.match(uri)) { 

    // If it returns 1 - then it matches the Uri defined in onCreate 
     case 1: 

      // The desired file name is specified by the last segment of the 
      // path 
      // E.g. 
      // 'content://com.stephendnicholas.gmailattach.provider/Test.txt' 
      // Take this and build the path to the file 
      // String fileLocation = getContext().getCacheDir() + File.separator + uri.getLastPathSegment(); 
      Integer mediaID = Integer.valueOf(uri.getLastPathSegment()); 

      if (_mediaData == null) { 
       _mediaData = new MediaData(); 
      } 
      Media m = _mediaData.get(mediaID); 

      // Create & return a ParcelFileDescriptor pointing to the file 
      // Note: I don't care what mode they ask for - they're only getting 
      // read only 
      ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(m.filePath), ParcelFileDescriptor.MODE_READ_ONLY); 
      return pfd; 

      // Otherwise unrecognised Uri 
     default: 
      Log.v(TAG, "Unsupported uri: '" + uri + "'."); 
      throw new FileNotFoundException("Unsupported uri: " + uri.toString()); 
    } 
} 

allora avete bisogno nel manifesto il riferimento al vostro ContentProvider, nel mio caso è stato

<provider 
     android:name=".contentproviders.MediaContentProvider" 
     android:authorities="com.way.srl.HandyWay.contentproviders.media" > 
    </provider> 

e poi usare in questo modo

Intent intent = new Intent(); 
intent.setAction(Intent.ACTION_VIEW); 
intent.setDataAndType(Uri.parse("content://" + MediaContentProvider.AUTHORITY + "/" + m.id), "image/jpg"); 

nel mio caso m è un'entità che memorizzare un id che puntano a un db SQLite e io uso una classe che recuperare i dati per popolare di nuovo l'oggetto (con _ mediaData), si può semplicemente modificare il codice in base alle proprie esigenze

questo modo ho risolto il problema esattamente nella mia richiesta

+0

Questa è una buona risposta, ma Google ha fornito un "FileProvider" da questo post. ecco un tutorial: http://developer.android.com/reference/android/support/v4/content/FileProvider.html – DaMachk

0

Ho capito che questo fallback non è necessario. I dispositivi con Google Play sono garantiti per avere almeno 2 GB disponibili in Environment.getExternalStorageDirectory().

Suppongo che nel Galaxy Nexus questa sia una partizione nella memoria interna contrassegnata come esterna. Mostrerò un avviso solo se non è disponibile.

+2

Sort of. Il Galaxy Nexus ha sicuramente una "memoria esterna" anche se è interno e non rimovibile. Tuttavia, sui dispositivi con memoria rimossa può essere non presente; e su dispositivi che fanno memoria di massa USB può non essere disponibile mentre è montato su un computer esterno. –

Problemi correlati