我在SD卡上有一个图像,需要在图像视图上显示
问题是,在解码之后,质量似乎恶化了.有没有什么方法可以保持质量,同时保留记忆?
或者,如果我使用更大的图像,是否有任何方法可以保留内存(避免加载太大的位图)和缩放? (我需要保持原始图像的大小)
谢谢你的帮助.
public Bitmap decodeFile(String pubKey, int bookPageID, int type)
throws IOException {
Bitmap b = null;
File f = null;
String uri = null;
FileInputStream fis = null;
Log.d(TAG,"pageID to read: " + bookPageID);
IRIssue issue = Broker.model.issueDataStore.getIRIssue(pubKey);
String imageFolder = IRConstant.issueFolder(issue.year, issue.month, issue.day, issue.pubKey);
// pageID - 1 since the page is an array (start at 0) , but page ID start at 1
if (type == 2){
uri = imageFolder + issue.vol[0].pages[bookPageID - 1].graphicUri;
}else {
uri = imageFolder + issue.vol[0].pages[bookPageID - 1].textUri;
}
f = new File(uri);
Log.d(TAG,"is file: " + uri + " exist?" + f.exists());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inInputShareable = true;
options.inJustDecodeBounds = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
fis = new FileInputStream(f);
b = BitmapFactory.decodeStream(fis, null, options);
fis.close();
return b;
}
解决方法:
以下代码使用Displaying Bitmaps Efficiently中的几个概念
首先关闭位图读取是在后台线程中完成的,我在inputStream上使用mark / reset(用BufferedInputstream包装),当我们试图找出计算尺度时要使用的图像大小时,不要从流中读取更多内容因子.下面的示例代码对图像进行子采样,以匹配320×240像素的大小.在非示例代码中,可以使用简单的回调接口将位图从onPostExecute发送到实现类(回调接口实现器).或者直接将视图作为AsyncTask的成员提供,并在onPostExecute中设置位图.
使用(我的设备上的示例下载图像)调用代码:
BitmapTask task = new BitmapTask(getContentResolver());
task.execute(Uri.parse("file:///storage/emulated/0/Download/download.jpg"));
有问题的课程
private static class BitmapTask extends AsyncTask {
// prevent mem leaks
private WeakReference mWeakContentResolver;
public BitmapTask(ContentResolver resolver) {
mWeakContentResolver = new WeakReference(resolver);
}
@Override
protected Bitmap doInBackground(Uri... params) {
Bitmap bitmap = null;
ContentResolver resolver = mWeakContentResolver.get();
if (resolver != null) {
BufferedInputStream stream = null;
try {
stream = new BufferedInputStream(
resolver.openInputStream(params[0]));
stream.mark(1 * 1024);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
// Find out size of image
BitmapFactory.decodeStream(stream, null, options);
try {
stream.reset();
} catch (IOException e) {
Log.d(TAG, "reset failed");
}
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
Log.d(TAG, "w, h, mime " + imageWidth + " , " + imageHeight
+ " , " + imageType);
options.inJustDecodeBounds = false;
// Calculate down scale factor
options.inSampleSize = calculateInSampleSize(options, 320,
240);
return BitmapFactory.decodeStream(stream, null, options);
} catch (FileNotFoundException e) {
bitmap = null;
} finally {
IOUtils.closeStreamSilently(stream);
}
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
Log.d(TAG,
"bitmap result: "
+ ((result != null) ? "" + result.getByteCount()
: "0"));
result.recycle();
}
}
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and
// keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
编辑:对于大型输入流可能存在标记/重置技术的问题,SkImageDecoder :: Factory返回null有时可以在日志中看到,导致空位图,关于此问题的其他SO问题:SkImageDecoder::Factory returned null.它可以通过以下方式修复:再次重新启动流变量stream = new resolver.openInputStream(params [0]));在doInBackground中返回之前
编辑2:如果你必须保留图像大小但不想限制内存使用,你可以使用options.inPreferredConfig = Bitmap.Config.RGB_565;将每个像素的内存减半,但要记住图像可能不再具有高质量(实验!).
标签:android,android-layout,image,bitmap,android-largeheap
来源: https://codeday.me/bug/20190728/1564400.html