我正在尝试构建一个允许ContentProvider
从原始图像中提取缩略图的功能。
以下是实施:
@Override
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException
{
[Uri handling stuff]
return openPipeHelper(image, "unused", null, null, this);
}
@Override
public void writeDataToPipe(@NonNull ParcelFileDescriptor output, @NonNull Uri uri, @NonNull String mimeType, @Nullable Bundle opts, @Nullable Void args)
{
final String where = Meta.URI_SELECTION;
final String[] whereArgs = new String[]{uri.toString()};
Meta.ImageType imageType = null;
try(Cursor metaCursor = query(
Meta.META_URI, new String[] { Meta.TYPE },
where, whereArgs, null, null))
{
if (metaCursor != null && metaCursor.moveToFirst())
imageType = Meta.ImageType.fromInt(metaCursor.getInt(metaCursor.getColumnIndex(Meta.TYPE)));
}
byte[] thumbData;
//noinspection ConstantConditions
try(AssetFileDescriptor fd = getContext().getContentResolver().openAssetFileDescriptor(uri, "r"))
{
if (imageType == null || imageType == Meta.ImageType.UNPROCESSED)
{
imageType = ImageUtil.getImageType(getContext(), uri);
// Update the image type
ContentValues value = new ContentValues(1);
value.put(Meta.TYPE, imageType.getValue());
update(Meta.META_URI, value, where, whereArgs);
}
switch(imageType)
{
case TIFF:
thumbData = ImageUtil.getTiffImage(fd.getParcelFileDescriptor().getFd());
break;
default:
thumbData = ImageUtil.getRawThumb(fd.getParcelFileDescriptor().getFd());
break;
}
}
catch (IOException e)
{
Log.e(TAG, ": Failed to open: " + uri, e);
return;
}
if (thumbData == null)
{
Log.e(TAG, ": Failed to extract: " + uri);
return;
}
try (FileOutputStream fout = new FileOutputStream(output.getFileDescriptor()))
{
fout.write(thumbData, 0, thumbData.length); // FAILS HERE
Log.d(TAG, "--End openFile: " + uri);
}
catch (IOException e)
{
Log.e(TAG, "*Fail openFile: " + uri, e);
}
}
代码使用PipeDataWriter
将来自本机(jni)解码缩略图ImageUtil.getRawThumb
的byte []放入将为fout.write(thumbData, 0, thumbData.length)
提供的管道openFile
的读取端}。
然而,当我加载几百张图像时,我发现5-10%的图像失败,错误类似于:
Glide正在调用03-24 23:34:49.022 26890-28130 / com.anthonymandra.rawdroidpro E / MetaProvider:* open openFile: 内容://com.android.externalstorage.documents/tree/0000-0000%3A_largeSet/document/0000-0000%3A_largeSet%2FKyoto-255.CR2 java.io.IOException:写入失败:EPIPE(断管) 在libcore.io.IoBridge.write(IoBridge.java:498) 在java.io.FileOutputStream.write(FileOutputStream.java:186) 在 的 com.anthonymandra.content.MetaProvider.writeDataToPipe(MetaProvider.java:270) 在 com.anthonymandra.content.MetaProvider.writeDataToPipe(MetaProvider.java:40) 在 android.content.ContentProvider $ 1.doInBackground(ContentProvider.java:1712) 在android.os.AsyncTask $ 2.call(AsyncTask.java:295) 在java.util.concurrent.FutureTask.run(FutureTask.java:237) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 在 java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:588) 在java.lang.Thread.run(Thread.java:818) 引起:android.system.ErrnoException:写入失败:EPIPE(破碎 管) at libcore.io.Posix.writeBytes(Native Method) 在libcore.io.Posix.write(Posix.java:271) 在libcore.io.BlockGuardOs.write(BlockGuardOs.java:313) 在libcore.io.IoBridge.write(IoBridge.java:493) 在java.io.FileOutputStream.write(FileOutputStream.java:186) 在 com.anthonymandra.content.MetaProvider.writeDataToPipe(MetaProvider.java:270) 在 com.anthonymandra.content.MetaProvider.writeDataToPipe(MetaProvider.java:40) 在 android.content.ContentProvider $ 1.doInBackground(ContentProvider.java:1712) 在android.os.AsyncTask $ 2.call(AsyncTask.java:295) 在java.util.concurrent.FutureTask.run(FutureTask.java:237) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 在 java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:588) 在java.lang.Thread.run(Thread.java:818)
ContentResolver.openInputStream
,它正在使用“核心计数”线程来加载图像。
之前我只是通过Glide的自定义加载器加载缩略图而没有问题。我猜测底层“管道”系统存在一些并发性限制。关于这个主题的大多数问题都没有得到令人满意的答案。这里有什么明显的错误,或者我是否超出了系统的能力?