Android Oreo出现IOException: Resetting to invalid mark:一加5/5T图库图片缩放异常
解决OxygenOS 8.0.0上图片缩放抛出IOException: Resetting to invalid mark的问题
这个问题我之前在适配OnePlus机型时也碰到过,本质是OxygenOS 8.0.0的图库返回的InputStream不支持mark/reset机制,而相机拍摄的图片对应的流(比如FileInputStream)天然支持该机制,所以相机图能正常处理,图库图却报错。
问题根源
当你用BitmapFactory.decodeStream()或者自定义缩放逻辑调用了流的mark()和reset()时,如果原输入流不支持mark(或者标记的位置无效),就会抛出IOException: Resetting to invalid mark。OnePlus 5/5T的OxygenOS 8.0.0对图库文件的流做了定制,导致它不支持标准的mark/reset操作。
解决方案:将输入流转换为支持mark的ByteArrayInputStream
最稳妥的办法是先把图库返回的流读取成字节数组,再用ByteArrayInputStream包装——这个类天生支持mark/reset,不管原流是什么实现。
第一步:封装获取支持mark的流的方法
private InputStream getMarkSupportedInputStream(Context context, Uri imageUri) throws IOException { InputStream originalStream = context.getContentResolver().openInputStream(imageUri); if (originalStream == null) { return null; } // 将原流读取到字节数组 ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = originalStream.read(buffer)) != -1) { byteStream.write(buffer, 0, bytesRead); } originalStream.close(); // 返回支持mark/reset的ByteArrayInputStream return new ByteArrayInputStream(byteStream.toByteArray()); }
第二步:修改你的缩放逻辑
把原来直接使用ContentResolver.openInputStream()的地方,换成上面的方法。比如完整的采样缩放代码:
public Bitmap getScaledBitmap(Context context, Uri imageUri, int targetWidth, int targetHeight) throws IOException { InputStream markSupportedStream = getMarkSupportedInputStream(context, imageUri); if (markSupportedStream == null) { return null; } BitmapFactory.Options options = new BitmapFactory.Options(); // 先只获取图片尺寸,不加载完整Bitmap options.inJustDecodeBounds = true; BitmapFactory.decodeStream(markSupportedStream, null, options); // 重置流,因为上面的decodeStream已经读取了一部分内容 markSupportedStream.reset(); // 计算合适的采样率,避免OOM options.inSampleSize = calculateSampleSize(options, targetWidth, targetHeight); // 现在加载实际的Bitmap options.inJustDecodeBounds = false; Bitmap scaledBitmap = BitmapFactory.decodeStream(markSupportedStream, null, options); markSupportedStream.close(); return scaledBitmap; } private int calculateSampleSize(BitmapFactory.Options options, int targetWidth, int targetHeight) { int originalWidth = options.outWidth; int originalHeight = options.outHeight; int sampleSize = 1; if (originalHeight > targetHeight || originalWidth > targetWidth) { int halfHeight = originalHeight / 2; int halfWidth = originalWidth / 2; while ((halfHeight / sampleSize) >= targetHeight && (halfWidth / sampleSize) >= targetWidth) { sampleSize *= 2; } } return sampleSize; }
额外说明
- 为什么Glide/Picasso一开始失效?这两个库内部也依赖流的mark/reset来处理图片,遇到OxygenOS的定制流时同样会触发异常,所以换自己的缩放方案时也会碰到同样的问题。
- 内存注意事项:如果图片特别大,读取成字节数组可能会占用较多内存,这时候可以结合
ParcelFileDescriptor和FileInputStream试试,但ByteArrayInputStream是兼容性最好的方案。
内容的提问来源于stack exchange,提问作者pratiked
相关产品推荐
相关产品推荐

