在android中使用sdcard在view pager上显示大图像

时间:2013-12-26 14:23:41

标签: android out-of-memory

我有一个问题,我有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;
    }

提前致谢。

3 个答案:

答案 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表示您应该使用的构造函数。