EPIPE(断管)

时间:2017-03-24 23:29:22

标签: java android android-contentprovider

我正在尝试构建一个允许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%的图像失败,错误类似于:

  

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)

Glide正在调用

ContentResolver.openInputStream,它正在使用“核心计数”线程来加载图像。

之前我只是通过Glide的自定义加载器加载缩略图而没有问题。我猜测底层“管道”系统存在一些并发性限制。关于这个主题的大多数问题都没有得到令人满意的答案。这里有什么明显的错误,或者我是否超出了系统的能力?

0 个答案:

没有答案