传递已读 FD 包裹:何时关闭



要通过绑定器传递大量数据,我们创建一个管道,然后将管道的读取端作为ParcelFileDescriptor传递到绑定器,并启动一个线程将数据写入管道的写入端。它基本上看起来像这样:

  public void writeToParcel(Parcel out, int flags) {
    ParcelFileDescriptor[] fds;
    try {
      fds = ParcelFileDescriptor.createPipe();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
    out.writeParcelable(fds[0], 0);
    byte[] bytes = ...; // Marshall object data to bytes
    write(bytes, fds[1]); // Starts a thread to write the data
  }

接收端从管道的读取端读取数据。它看起来像这样:

ParcelFileDescriptor readFd = in.readFileDescriptor();
FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(readFd);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] b = new byte[16 * 1024];
int n;
try {
  while ((n = fis.read(b)) != -1) {
    out.write(b, 0, n);
  }
} catch (IOException e) {
  throw new RuntimeException(e);
} finally {
  try {
    Log.i(TAG, "Closing read file descriptor..."); // I see this
    fis.close();
    Log.i(TAG, "Closed read file descriptor"); // And I see this
  } catch (IOException e) {
    e.printStackTrace();
  }
}

这有效,但是当启用 strictmode 时,我们崩溃了:

 01-03 14:26:48.099 E/StrictMode(25346): A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks. 
 01-03 14:26:48.099 E/StrictMode(25346): java.lang.Throwable: Explicit termination method 'close' not called 
 01-03 14:26:48.099 E/StrictMode(25346):    at dalvik.system.CloseGuard.open(CloseGuard.java:223) 
 01-03 14:26:48.099 E/StrictMode(25346):    at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:192) 
 01-03 14:26:48.099 E/StrictMode(25346):    at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:181) 
 01-03 14:26:48.099 E/StrictMode(25346):    at android.os.ParcelFileDescriptor.createPipe(ParcelFileDescriptor.java:425) 
 01-03 14:26:48.099 E/StrictMode(25346):    at com.clover.sdk.FdParcelable.writeToParcel(FdParcelable.java:118) 

第 118 行是管道的创建(ParcelFileDescriptor.createPipe())。

因此,发送方似乎需要关闭读取端和写入端。我的问题是我不知道什么时候可以关闭阅读结束,因为我不知道读者什么时候会完成阅读。

我错过了什么?

  1. 完成写入后,立即关闭输出流。

  2. 使用者始终负责在完成阅读后立即关闭其输入流。这不是您的责任(除非您也作为消费者行事)。

您所描述的类似于我打开一个FileOutputStream(我正在使用 API)并期望运行时为我关闭它,只是因为我在使用完它时没有显式关闭它。

因此,将FD发送到Parcel中,使用它的人负责关闭它。他们可以使用这样的东西:

val fd = parcel.readFileDescriptor()
val input = ParcelFileDescriptor.AutoCloseInputStream(fd)
// Use input. When #close() is called it will also close the FD.

请参阅:https://developer.android.com/reference/android/os/ParcelFileDescriptor.AutoCloseInputStream

您可以在客户端 SDK 库中隐藏此实现。无论如何,请为消费者记录好。

相关内容

  • 没有找到相关文章

最新更新