自定义ContentProvider - openInputStream(),openOutputStream()

han*_*asm 17 file-io android android-contentprovider

内容提供程序/解析程序API提供了一种使用URI openInputStream()openOutputStream()方法在进程之间传输数据的复杂但强大的方法.自定义内容提供商能够openFile()使用自定义代码覆盖该方法,以有效地将URI解析为Stream; 但是,方法签名openFile()具有ParcelFileDescriptor返回类型,并且不清楚如何为此方法返回动态生成的内容生成正确的表示.

从内容提供程序返回内存映射的InputStream?

是否有ContentProvider.openFile()现有代码库中动态内容实现方法的示例?如果没有,你可以建议这样做的源代码或过程吗?

Han*_*ner 24

从总是有用的CommonsWare中查看这个很棒的示例项目.它允许您创建一个ParcelFileDescriptor管道,其中一端是您想要的任何InputStream,另一侧是接收应用程序:

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

关键部分是在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]);
  }
Run Code Online (Sandbox Code Playgroud)

然后创建一个保持管道满的线程:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 知道为什么我在使用这个提供程序时遇到大量请求时会出现错误:java.io.IOException:write failed:java上的libcore.io.IoBridge.write(IoBridge.java:502)中的EPIPE(Broken pipe). io.FileOutputStream.write(FileOutputStream.java:186) (2认同)
  • 我和Malachiasz有同样的问题.有没有人在这方面取得任何进展? (2认同)

Jef*_*key 2

MemoryFile 支持此功能,但公共 API 尚未最终确定。

  • 是的,MemoryFile.java 目前有一个 `public ParcelFileDescriptor getParcelFileDescriptor()` 方法。这是作为 Donut 的一部分提交的,但正如杰夫所说,尚未最终确定。我已经确认这个“概念”至少有效,并且当前可以使用反射来完成。但它很脏,不推荐:)不幸的是,即使是 `ParcelFileDescriptor.fromSocket()` 也不能使用,因为 `Memory.isMemoryFile()` 会抛出异常,因为套接字既不是 PFD 也不是内存文件。 (2认同)
  • 小心内存文件。如果我理解正确的话,它将文件的全部内容存储在内存中,因此您不能使用大于可用内存的文件。 (2认同)