Domanda

Ho alcuni file di grandi dimensioni (immagini e video), che ho bisogno di memorizzare in un fornitore di contenuti. La documentazione Android indica ...

  

Se si sta esponendo i dati di byte che di   troppo grande per mettere in tabella stessa -   come ad esempio un file di grandi dimensioni bitmap - il   campo che espone i dati per i clienti   dovrebbe in realtà contenere un contenuto: URI   stringa. Questo è il campo che dà   clienti l'accesso al file di dati. Il   record deve avere anche un altro campo,   denominato "_data" che elenca le esatte   percorso del file sul dispositivo per quel file.   Questo campo non è destinato ad essere letto   da parte del cliente, ma dal   ContentResolver. Il cliente chiamerà   ContentResolver.openInputStream () su   il campo utente rivolto tiene l'URI   per la voce. La volontà ContentResolver   richiedere il campo "_data" per quel   registrare, sia perché ha una maggiore   i permessi di un cliente, si deve   essere in grado di accedere direttamente quel file   e restituire un involucro di lettura per il file   al cliente.   - http://developer.android.com/guide/topics /providers/content-providers.html#creating

Sto avendo qualche difficoltà a trovare un esempio. In particolare desidero utilizzare l'immagine bitmap nel contesto di un ImageView. Si consideri il seguente codice quasi-codice (non funziona) ...

ImageView iv = ....
String iconUri = cursor.getString(cursor.getColumnIndex(Table.ICON));
iv.setImageURI(Uri.parse(iconUri));

Le osservazioni / Problemi ...

  1. Come può la stored / recuperare uri essere ricostruito in modo corretto? (È il testo della tabella)
  2. Le marche di implementazione setImageURI utilizzo del contenuto openInputStream risolvere quindi questo dovrebbe funzionare.

    String scheme = mUri.getScheme();
    ...
    } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
            || ContentResolver.SCHEME_FILE.equals(scheme)) {
      try {
        d = Drawable.createFromStream(
                mContext.getContentResolver().openInputStream(mUri),
                null);
    

    - quadri / base / core / java / android / widget di / ImageView.java

ho ottenuto lavorando. Ho preso un suggerimento dal MediaStore e Mediaprovider. I file che contengono i dati sono denominati in base al fornitore di contenuti (directory), il nome della colonna, la riga id e il tipo di supporto. Il resolver contenuti quindi acquisisce il descrittore di file in questo modo ...

Uri iconUri = Uri.withAppendedPath(Table.getUri(cursor), Table.ICON);
ib.setImageURI(iconUri);

... e gli risponde di provider di contenuti in natura ...

@Override
public ParcelFileDescriptor openFile (Uri uri, String mode) {
int imode = 0;
if (mode.contains("w")) imode |= ParcelFileDescriptor.MODE_WRITE_ONLY;
if (mode.contains("r")) imode |= ParcelFileDescriptor.MODE_READ_ONLY;
if (mode.contains("+")) imode |= ParcelFileDescriptor.MODE_APPEND;
List<String> pseg = uri.getPathSegments();
if (pseg.size() < 3) return null;

try {
    File filePath = filePathFromRecord(pseg.get(2), pseg.get(1));
    return ParcelFileDescriptor.open(filePath, imode);
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
return null;
}
È stato utile?

Soluzione

La soluzione offre phreed nella metà inferiore della domanda è fondamentalmente corretto. Cercherò di aggiungere qualche dettaglio in più qui.

Quando si esegue getContentResolver().openInputStream(...), content resolver andrà al vostro fornitore di contenuti e chiamare il suo metodo openFile. Questo è come gli sguardi openFile in ContentProvider.java :

public ParcelFileDescriptor openFile(Uri uri, String mode)
     throws FileNotFoundException {
 throw new FileNotFoundException("No files supported by provider at "
         + uri);
}

Quindi questo spiega dove i "Nessun file supportati ..." errore viene esattamente da! È possibile ottenere intorno a questo sovrascrivendo il metodo openFile nella sottoclasse e fornendo una propria implementazione. E 'pulito: si ottiene un perfetto controllo di cui i file vengono inseriti quando qualsiasi client fa openInputStream o openOutputStream.

Esempio di codice in questione di phreed dà un suggerimento come l'implementazione potrebbe sembrare. Ecco la mia versione leggermente modificata che crea anche directory e file, se necessario. Sono novizio in questo roba così questo potrebbe non essere il modo ottimale di fare le cose, ma dà un'idea. Per prima cosa, si dovrebbe probabilmente verificare se la memorizzazione esterna è disponibile.

@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
    File root = new File(Environment.getExternalStorageDirectory(), 
            "/Android/data/com.example.myapp/cache");
    root.mkdirs();
    File path = new File(root, uri.getEncodedPath());
    // So, if the uri was content://com.example.myapp/some/data.xml,
    // we'll end up accessing /Android/data/com.example.myapp/cache/some/data.xml

    int imode = 0;
    if (mode.contains("w")) {
            imode |= ParcelFileDescriptor.MODE_WRITE_ONLY;
            if (!path.exists()) {
                try {
                    path.createNewFile();
                } catch (IOException e) {
                    // TODO decide what to do about it, whom to notify...
                    e.printStackTrace();
                }
            }
    }
    if (mode.contains("r")) imode |= ParcelFileDescriptor.MODE_READ_ONLY;
    if (mode.contains("+")) imode |= ParcelFileDescriptor.MODE_APPEND;        

    return ParcelFileDescriptor.open(path, imode);
}

Altri suggerimenti

Android fornisce il metodo di supporto openFileHelper () che rende l'implementazione del metodo OpenFile () molto facile. Tutto quello che dovete fare, per utilizzare questo metodo, è quello di fornire la posizione del file in una colonna denominata “_data”.

@Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
      throws FileNotFoundException {
   if (URI_MATCHER.match(uri) != PHOTO_ID) {
      throw new IllegalArgumentException
            ("URI invalid. Use an id-based URI only.");
   }
   return openFileHelper(uri, mode);
}

Clicca qui per i dettagli

C'è un problema di scrittura di file però. In che modo il fornitore di contenuti conosce poi la scrittura è completo?

Quando si chiude un OutputStream ottenuto tramite un ContentResolver.openOutputStream () ho desiderio per il corrispondente (personalizzato) ContentProvider di eseguire una certa azione personalizzata. Attualmente sto usando la creazione di un FileObserver su un temporanea il file ma sembra che il modo sbagliato per farlo fare. Il mio primo pensiero è stato quello di sottotipo ParcelFileDescriptor prodotto dal ContentProvider.openFile () metodo, ma che non sembra funzionare per me.

Detto questo ci sono stati alcuni errori che hanno provocato l'utilizzo MyParcelFileDescriptor.

  • non mi assicuro che il descrittore di file non sarebbe garbage collection prematuramente.
  • Non ha cercato di override alla fine () (la documentazione sembra suggerire che essere il luogo per fare questo, ma close () sembrava essere la scelta giusta a me.

Linea di fondo, c'è qualche interazione tra gli oggetti file come si è visto dal ContentResolver e quelli della ContentProvider ?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top