2010-01-27 23 views
14

Las API del proveedor de contenido/resolver proporcionan una forma complicada pero sólida de transferir datos entre procesos utilizando un URI y los métodos openInputStream() y openOutputStream(). Los proveedores de contenido personalizado tienen la capacidad de anular el método openFile() con código personalizado para resolver efectivamente un URI en un Stream; sin embargo, la firma de método de openFile() tiene un tipo de devolución ParcelFileDescriptor y no está claro cómo se puede generar una representación adecuada para que el contenido generado dinámicamente regrese de este método.Custom ContentProvider - openInputStream(), openOutputStream()

Returning a memory mapped InputStream from a content provider?

¿Hay ejemplos de la aplicación de ContentProvider.openFile() método para contenido dinámico en la base de código existente? Si no, ¿puede sugerir el código fuente o el proceso para hacerlo?

Respuesta

1

MemoryFile admite esto, pero la API pública no se ha finalizado.

+0

¿hay planes para incluir una conversión entre una y memoryfile parcelfiledescriptor en el futuro? Algo en ese sentido sería más agradable que saturar/contaminar el sistema de archivos con archivos temporales con tiempos de vida desconocidos. Quizás haya alguna forma de detectar el cierre de la transmisión dentro del proveedor de contenido que podría ofrecer una forma más segura de limpieza después de usted mismo. Me preocupa enviar archivos adjuntos a un cliente de correo electrónico (gmail/standaed), aunque estoy seguro de que hay otros lugares donde podrían surgir estos problemas. – hannasm

+1

Sí, MemoryFile.java actualmente tiene el método 'public ParcelFileDescriptor getParcelFileDescriptor()'. Esto fue cometido como parte de Donut, pero como dijo Jeff, aún no está finalizado. He confirmado que el "concepto" al menos funciona, y se puede hacer actualmente, utilizando la reflexión. Sin embargo, es muy sucio y no recomendado :) Desafortunadamente, incluso 'ParcelFileDescriptor.fromSocket()' no se puede usar porque 'Memory.isMemoryFile()' arroja una excepción porque el socket no es ni un PFD ni un archivo de memoria. – Joe

+1

Cuidado con MemoryFile. Si lo entiendo correctamente, almacena todo el contenido de un archivo en la memoria, por lo que no puede usar archivos más grandes que la memoria disponible. –

23

Echa un vistazo a este gran proyecto de ejemplo del siempre útil CommonsWare. Te permite crear un tubo ParcelFileDescriptor con cualquier InputStream desea, por un lado, y la aplicación receptora en el otro lado:

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

Las partes principales son la creación de la tubería en 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]); 
    } 

continuación, crear un hilo que mantiene el tubo lleno:

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

perfecto justo lo que estaba buscando ... – siliconeagle

+0

Utilizo una lib de terceros que solicita archivos a través de un proveedor de contenido y por alguna razón los datos en el otro extremo llegan (y aquí he tenido cuidado de decir) de manera diferente al devolver el ParcelFileDescriptor de esta manera o al usar un archivo real como este: ParcelFileDescriptor.open (privateFile, ParcelFileDescriptor.MODE_READ_ONLY) – TacB0sS

+1

Alguna idea de por qué a veces recibo un error cuando uso este proveedor con mayor cantidad de solicitudes: java.io.IOException: write failed : EPIPE (Broken pipe) en libcore.io.IoBridge.write (IoBridge.java:502) en java.io.FileOutputStream.write (FileOutputStream.java:186) – Malachiasz