【问题标题】:ViewFlipper inside ViewPager - OutOfMemoryViewPager 中的 ViewFlipper - OutOfMemory
【发布时间】:2014-04-03 18:23:01
【问题描述】:

我的应用中有 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);
    }

你能告诉我我做错了什么吗?在过去的几天里,这让我发疯:(

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

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

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

    顺便说一句 - 您正在使用的资源大小只有 60KB 这一事实并没有改变任何东西。事实上 - 图像内存大小(千比特/兆)对分配的位图没有任何影响。只有分辨率才能有所作为!

    编辑

    因为在 onCreateView() 方法中 imageView 尺寸仍然为零 - 您应该仅在获得尺寸后执行解码:

    --- 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 没有任何意义。

    【讨论】:

    • 感谢您的回复.. 我按照这个 example 关注!它要求我们仅发送分辨率。但是,当我按照您的建议说main_img.getHeight() 时,它只显示空白图像。因为它不知道确切的宽度或高度。我在这里错过了什么吗?
    • @Naveen:你遵循了正确的例子,但我很伤心 - 你理解错了。 BitmapFactory.decodeResource() 知道计算原始图像尺寸。你得到空位图,因为尚未在该阶段计算 imageView 的高度和宽度( onCreateView 方法),因此在该阶段 imageView 的高度和宽度为零。按照这篇文章如何检测何时应用实际尺寸 - stackoverflow.com/questions/4142090/…
    • 对不起,我仍然很困惑.. 即使在阅读了您在上述评论中发布的线程之后,我仍不完全清楚如何获取图像的宽度和高度。您能否指出一些使用 ViewPager 滑动图像并在其中使用 ViewFlipper 的工作示例。抱歉,我的 Google 搜索没有得到想要的结果 :(
    • @Naveen:您不需要获取图像的宽度和高度。你需要得到imageView的高度和宽度!这是两件不同的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 2012-10-13
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    相关资源
    最近更新 更多