Phương pháp này sẽ đọc thông tin tiêu đề từ hình ảnh để xác định kích thước của nó, sau đó đọc hình ảnh và chia tỷ lệ theo kích thước mong muốn mà không cần cấp phát bộ nhớ cho hình ảnh có kích thước gốc đầy đủ.
Nó cũng sử dụng BitmapFactory.Options.inPurgeable, có vẻ là một tài liệu thưa thớt nhưng tùy chọn mong muốn để ngăn chặn ngoại lệ OoM khi sử dụng nhiều bitmap. CẬP NHẬT: không còn sử dụng inPurgeable, xem this note từ Romain
Nó hoạt động bằng cách sử dụng BufferedInputStream để đọc thông tin tiêu đề cho hình ảnh trước khi đọc toàn bộ hình ảnh qua InputStream.
/**
* Read the image from the stream and create a bitmap scaled to the desired
* size. Resulting bitmap will be at least as large as the
* desired minimum specified dimensions and will keep the image proportions
* correct during scaling.
*/
protected Bitmap createScaledBitmapFromStream(InputStream s, int minimumDesiredBitmapWith, int minimumDesiredBitmapHeight) {
final BufferedInputStream is = new BufferedInputStream(s, 32*1024);
try {
final Options decodeBitmapOptions = new Options();
// For further memory savings, you may want to consider using this option
// decodeBitmapOptions.inPreferredConfig = Config.RGB_565; // Uses 2-bytes instead of default 4 per pixel
if(minimumDesiredBitmapWidth >0 && minimumDesiredBitmapHeight >0) {
final Options decodeBoundsOptions = new Options();
decodeBoundsOptions.inJustDecodeBounds = true;
is.mark(32*1024); // 32k is probably overkill, but 8k is insufficient for some jpgs
BitmapFactory.decodeStream(is,null,decodeBoundsOptions);
is.reset();
final int originalWidth = decodeBoundsOptions.outWidth;
final int originalHeight = decodeBoundsOptions.outHeight;
// inSampleSize prefers multiples of 2, but we prefer to prioritize memory savings
decodeBitmapOptions.inSampleSize= Math.max(1,Math.min(originalWidth/minimumDesiredBitmapWidth, originalHeight/minimumDesiredBitmapHeight));
}
return BitmapFactory.decodeStream(is,null,decodeBitmapOptions);
} catch(IOException e) {
throw new RuntimeException(e); // this shouldn't happen
} finally {
try {
is.close();
} catch(IOException ignored) {}
}
}
Bạn cũng có thể cần phải thực hiện một cuộc gọi GC rõ ràng trước khi gọi BitmapFactory.decodeStream, như mỗi câu trả lời này: http://stackoverflow.com/questions/6718855/using-caching-to-improve-scrolling-performance -in-an-android-listview-with-images/7245318 # 7245318 – emmby
nó có thể có ý nghĩa để sử dụng mới/đóng thay vì đánh dấu/thiết lập lại trên một FileInputStream. Nhưng ý tưởng là tốt. – kellogs
Tại sao tôi nhận được 'java.io.IOException: Mark đã bị vô hiệu' trên 'is.reset(); ' – sancho21