2010-01-27 2 views
14

Le API del provider di contenuti/resolver forniscono un metodo complicato, ma efficace per trasferire dati tra processi utilizzando un URI e i metodi openInputStream() e openOutputStream(). I fornitori di contenuti personalizzati hanno la possibilità di ignorare il metodo openFile() con codice personalizzato per risolvere efficacemente un URI in un Stream; tuttavia, la firma del metodo di openFile() ha un tipo di ritorno ParcelFileDescriptor e non è chiaro in che modo si possa generare una rappresentazione corretta per il contenuto generato dinamicamente da restituire da questo metodo.ContentProvider personalizzato - openInputStream(), openOutputStream()

Returning a memory mapped InputStream from a content provider?

ci sono esempi di attuazione ContentProvider.openFile() metodo per il contenuto dinamico nella base di codice esistente? Se no, puoi suggerire codice sorgente o processo per farlo?

risposta

1

MemoryFile supporta questo, ma l'API pubblica non è stata finalizzata.

+0

Ci sono piani per includere una conversione tra un file di memoria e parcelfiledescriptor in futuro? Qualcosa lungo queste linee sarebbe più bello che ingombrare/inquinare il filesystem con file temporanei che hanno una durata sconosciuta. Forse c'è un modo per rilevare la chiusura del flusso all'interno del fornitore di contenuti che potrebbe offrire un modo un po 'più sicuro di pulizia dopo te stesso? Mi preoccupo di inviare allegati a un client di posta elettronica (gmail/standaed) anche se sono sicuro che ci sono altri posti in cui potrebbero sorgere questi problemi. – hannasm

+1

Sì, MemoryFile.java ha attualmente un metodo 'public ParcelFileDescriptor getParcelFileDescriptor()'. Questo è stato commesso come parte di Donut, ma come diceva Jeff, non è ancora stato finalizzato. Ho confermato che il "concetto" funziona almeno, e può essere fatto al momento, usando la riflessione. È molto sporco però e non consigliato :) Sfortunatamente, anche 'ParcelFileDescriptor.fromSocket()' non può essere usato perché 'Memory.isMemoryFile()' genera un'eccezione perché il socket non è né un PFD né un file di memoria. – Joe

+1

Attenzione con MemoryFile. Se ho capito bene, memorizza l'intero contenuto di un file in memoria, quindi non puoi usare file più grandi della memoria disponibile. –

23

Dai un'occhiata a questo fantastico progetto di esempio dal sempre utile CommonsWare. Esso consente di creare un tubo ParcelFileDescriptor con qualsiasi InputStream si vuole da una parte, e l'applicazione di ricezione sul lato opposto:

https://github.com/commonsguy/cw-omnibus/tree/master/ContentProvider/Pipe

Le parti principali sono la creazione del tubo in openFile:

public ParcelFileDescriptor openFile(Uri uri, String mode) 
                 throws FileNotFoundException { 
    ParcelFileDescriptor[] pipe=null; 

    try { 
     pipe=ParcelFileDescriptor.createPipe(); 
     AssetManager assets=getContext().getResources().getAssets(); 

     new TransferThread(assets.open(uri.getLastPathSegment()), 
         new AutoCloseOutputStream(pipe[1])).start(); 
    } 
    catch (IOException e) { 
     Log.e(getClass().getSimpleName(), "Exception opening pipe", e); 
     throw new FileNotFoundException("Could not open pipe for: " 
      + uri.toString()); 
    } 

    return(pipe[0]); 
    } 

Quindi creare un thread che mantiene il pipe pieno:

static class TransferThread extends Thread { 
    InputStream in; 
    OutputStream out; 

    TransferThread(InputStream in, OutputStream out) { 
     this.in = in; 
     this.out = out; 
    } 

    @Override 
    public void run() { 
     byte[] buf = new byte[8192]; 
     int len; 

     try { 
      while ((len = in.read(buf)) > 0) { 
       out.write(buf, 0, len); 
      } 

      in.close(); 
      out.flush(); 
      out.close(); 
     } catch (IOException e) { 
      Log.e(getClass().getSimpleName(), 
        "Exception transferring file", e); 
     } 
    } 
} 
+3

perfetto proprio quello che stavo cercando ... – siliconeagle

+0

Io uso una lib di terze parti che richiede i file tramite un provider di contenuti e per qualche motivo i dati sull'altra estremità arrivano (e qui sono stato attento a dire) in modo diverso quando si restituisce il ParcelFileDescriptor in questo modo o quando si utilizza un file reale in questo modo: ParcelFileDescriptor.open (privateFile, ParcelFileDescriptor.MODE_READ_ONLY) – TacB0sS

+1

Qualsiasi idea del motivo ottengo un errore a volte quando si utilizza questo provider con una quantità maggiore di richieste: java.io.IOException: write failed : EPIPE (Tubo rotto) in libcore.io.IoBridge.write (IoBridge.java:502) in java.io.FileOutputStream.write (FileOutputStream.java:186) – Malachiasz