Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom ContentProvider - openInputStream(), openOutputStream()

The content provider/ resolver APIs provide a complicated, but robust way of transferring data between processes using a URI and the openInputStream() and openOutputStream() methods. Custom content providers have the ability to override the openFile() method with custom code to effectively resolve a URI into a Stream; however, the method signature of openFile() has a ParcelFileDescriptor return type and it is not clear how one might generate a proper representation for dynamically generated content to return from this method.

Returning a memory mapped InputStream from a content provider?

Are there examples of implementing ContentProvider.openFile() method for dynamic content in the existing code base? If not can you suggest source code or process for doing so?

like image 301
hannasm Avatar asked Jan 27 '10 15:01

hannasm


2 Answers

Check out this great example project from the always helpful CommonsWare. It lets you create a ParcelFileDescriptor pipe with whatever InputStream you want on one side, and the receiving application on the other side:

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

The key parts are creating the pipe 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]);
  }

Then create a thread that keeps the pipe full:

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);
        }
    }
}
like image 146
Hans-Christoph Steiner Avatar answered Sep 27 '22 19:09

Hans-Christoph Steiner


MemoryFile supports this, but the public API hasn't been finalized.

like image 28
Jeff Sharkey Avatar answered Sep 27 '22 21:09

Jeff Sharkey