ViewPager内的ViewFlipper - OutOfMemory

时间:2014-04-03 18:23:02

标签: android bitmap android-viewpager out-of-memory viewflipper

我的应用中有20张图片。所有图像均为640 * 360分辨率,每个图像不超过60KB。

我利用Viewpager来滑动图像。并在ViewPager中使用ViewFlipper来翻转图像。当用户点击它时,我会显示图像的相应文本。

问题是当我来回滑动5次时,我得到OutOfMemory异常。我读了各种Stackoverflow线程here!,here!,here!和Handling Large Bitmaps Efficiently!但无法解决问题,

这是代码,

在Main_Fragment.java中,

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {

--- some code ---

--- some more code --- 

View v = inflater.inflate(R.layout.main_fragment, container,false);

viewAnimator = ((ViewAnimator) v.findViewById(R.id.cardFlipper));

TextView caption_text = (TextView) v.findViewById(R.id.caption_text);
caption_text.setText(caption.toUpperCase());

ImageView main_img = (ImageView) v.findViewById(R.id.main_img);

int mainimg_resID = getResources().getIdentifier(mainimg,"drawable",context.getPackageName());

Bitmap icon = decodeSampledBitmapFromResource(getResources(),mainimg_resID,640,360);

main_img.setImageBitmap(icon);

viewAnimator.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
  AnimationFactory.flipTransition((ViewAnimator) v,FlipDirection.LEFT_RIGHT);
}
});

return v;
}


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;
    }

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
            int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }
你能告诉我我做错了吗?这让我疯狂了过去几天:(

1 个答案:

答案 0 :(得分:0)

是的,我看到你正在做的事情非常错误:

Bitmap icon = decodeSampledBitmapFromResource(getResources(),mainimg_resID,640,360);

你弄错了:reqHeightreqWidth参数应该是图像视图的宽度和高度,而不是原始图像尺寸!!这就是calculateInSampleSize()的全部内容..

所以,您应该执行以下操作:

Bitmap icon = decodeSampledBitmapFromResource(getResources(),mainimg_resID,main_img.getWidth(), main_img.getHeight());

通过解码基于仅显示所需尺寸计算的比例的位图 - 结果位图分配将是最小的。

顺便说一下 - 您使用的资源大小只有60KB的事实不会改变任何东西。实际上 - 图像内存大小(Kilobites / Megas)对分配的位图没有任何影响。这只是解决方案的唯一因素!

修改

因为imageView维度在onCreateView()方法中仍然为零 - 你只有在得到它后才能进行解码:

--- some code ---

--- some more code --- 

View v = inflater.inflate(R.layout.main_fragment, container,false);

viewAnimator = ((ViewAnimator) v.findViewById(R.id.cardFlipper));

TextView caption_text = (TextView) v.findViewById(R.id.caption_text);
caption_text.setText(caption.toUpperCase());

final ImageView main_img = (ImageView) v.findViewById(R.id.main_img);

ViewTreeObserver vto = main_img.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {

            final ViewTreeObserver obs = main_img.getViewTreeObserver();

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            obs.removeOnGlobalLayoutListener(this);
            } else {
               obs.removeGlobalOnLayoutListener(this);
            }

            // do here the image decoding + setting the image to the image view
            Bitmap icon = decodeSampledBitmapFromResource(getResources(),mainimg_resID,main_img.getWidth(), main_img.getHeight());

            //  setImage....
      }

});

viewAnimator.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
    AnimationFactory.flipTransition((ViewAnimator) v,FlipDirection.LEFT_RIGHT);
    }
});

return v;

编辑2

永远不要将wrap_content用于ImageView。那是因为它强制视图的大小与原始图像(可能非常大)相反,而不是相反。在计算所需的比例时 - 整点是在ImageView维度与原始图像(资源/文件/流)维度之间进行比较。这就是为什么它没有任何意义使用wrap_content