Reputation: 2041
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?
Upvotes: 20
Views: 7959
Reputation: 2682
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);
}
}
}
Upvotes: 28
Reputation: 2483
MemoryFile supports this, but the public API hasn't been finalized.
Upvotes: 2