要在活页夹上传递大量数据,我们创建一个管道,然后将管道的读取端作为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())。
因此,似乎发送方需要关闭读取端和写入端。我的问题是我不知道何时可以关闭阅读端,因为我不知道阅读器何时才能完成阅读。
我想念什么?
答案 0 :(得分:0)
写完后,立即关闭输出流。
使用者始终有责任在完成阅读后立即关闭其输入流。这不是您的责任(除非您也充当消费者)。
您所描述的内容类似于我打开一个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库中隐藏此实现。无论如何,请为消费者做好记录。