我有一个问题,我有80到150张非常高分辨率的图像,我必须在视图寻呼机中显示它们。我编写了简单的解码机制,但在第二页之后得到OutofMemory Error。我尝试了很多,但无法找到确切的解决方案来避免这种情况。我自己的建议是,如果我们能够在图像视图中加载部分图像,那么我们可能会避免这种情况,但我不知道如何实现这一点。请就此提出任何解决方案。
代码:
private class MyPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return Integer.parseInt(pagesCount);
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0==((ImageView)arg1);
}
@Override
public void destroyItem(View container, int position, Object object) {
View view = (View)object;
((ViewPager) container).removeView(view);
view = null;
}
@Override
public View instantiateItem(View container, final int position) {
final ImageView imgPage = new ImageView(getApplicationContext());
/*imgPage.setImageURI(Uri.withAppendedPath(
Uri.parse(Environment.getExternalStorageDirectory()+"/MAGZ/"+magName+issueName), "" + (issueName+position)+".png"));*/
//imgPage.setImageBitmap(BitmapFactory.decodeFile(Environment.getExternalStorageDirectory()+"/MAGZ/"+magName+issueName+"/"+(issueName+position)));
//destroyItem(container, position, imgPage);
imgPage.setScaleType(android.widget.ImageView.ScaleType.FIT_XY);
imgPage.setImageDrawable(getImageFromSdCard(issueName+position));
//imgPage.setImageResource(getImageFromSdCard(issueName+position));
((ViewPager) container).addView(imgPage,0);
return imgPage;
}
}
public Drawable getImageFromSdCard(String imageName) {
Drawable d = null;
try {
String path = Environment.getExternalStorageDirectory()+"/MAGZ/"+magName+"/"+magName+issueName;
bitmap = BitmapFactory.decodeFile(path + "/" + imageName
+ ".png");
// d = new BitmapDrawable(bitmap);
d = new BitmapDrawable(decodeFile(new File(path+"/"+imageName+".png")));
// bitmap.recycle();
bitmap = null;
} catch (IllegalArgumentException e) {
bitmap = null;
}
return d;
}
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=550;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
提前致谢。
答案 0 :(得分:2)
inJustDecodeBounds& inSampleSize
您正在解析每个PagerAdapter调用时的高分辨率图像,如果您愿意将解码后的位图内存减少2(x / 2,x / 4 ... x:原始位图大小),则转到这method
<强> Bitmap.recycle()强>
一种非常方便的方法,当在正确的地方使用时,可以创造奇迹。我假设您正在设置BitmapDrawable或调用setImageBitmap到ImageView。在PagerAdapter的destroyItem()回调中添加以下代码段。
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View) object;
ImageView imageView = (ImageView) view.findViewById(R.id.image_view);
Drawable drawable = imageView.getDrawable();
if(drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if(bitmapDrawable != null) {
Bitmap bitmap = bitmapDrawable.getBitmap();
if(bitmap != null && !bitmap.isRecycled()) bitmap.recycle();
}
}
((ViewPager) container).removeView(view);
}
这个想法是,当从Pager中删除任何子视图时,它的位图应该被回收,这样你就不会依赖GC调用为你清除内存。
largeHeap = true
在Manifest.xml <application>
标记中添加此属性。无论在哪里支持largeHeap,它都会将堆内存增加到一个较大的值,甚至可以达到8次。
此外,一般情况下,不要对任何位图进行任何愚蠢的引用,只需解码它们并将其分配给View,其余的就会得到处理。
希望有所帮助。 :)
答案 1 :(得分:0)
我建议你look at official android developers sample code called BitmapFun and use it for your purpose。实际上你错过了o2.inPurgable=true;
而且没有必要使用o和o2,o已经足够了。
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//The new size we want to scale to
final int REQUIRED_SIZE=550;
//Find the correct scale value. It should be the power of 2.
int scale=1;
while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
scale*=2;
//Decode with inSampleSize
//BitmapFactory.Options o2 = new BitmapFactory.Options();
o.inSampleSize=scale;
o.inJustDecodeBounds = false;
o.inPurgealbe = true;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o);
} catch (FileNotFoundException e) {}
return null;
}
答案 2 :(得分:0)
从bitmap = BitmapFactory.decodeFile(path + "/" + imageName
+ ".png");
方法中删除行Drawable getImageFromSdCard(String imageName)
以开始。同时删除该方法中的位图变量,因为它已经不使用了,现在你已经删除了不必要的分配,你遇到的问题可能是GC根本不能处理自你做了两倍以来所做的垃圾/分配量那是必要的。该方法应如下所示:
public Drawable getImageFromSdCard(String imageName) {
Drawable d = null;
String path = Environment.getExternalStorageDirectory()+"/MAGZ/"+magName+"/"+magName+issueName;
d = new BitmapDrawable(decodeFile(new File(path+"/"+imageName+".png")));
return d;
}
在o
方法中重复使用decodeFile
变量,只需记住在第一次调用后翻转布尔值inJustDecodeBounds
。
另外,不要捕获运行时异常,不好的做法,因为运行时错误,它们就在那里。你抓住它们就可以隐藏真正的问题。
从pi版本4开始, BitmapDrawable(Bitmap bitmap)
构造函数已被弃用,checkout BitmapDrawable表示您应该使用的构造函数。