ViewPager with ImageView gives “java.lang.OutOfMemoryError: bitmap size exceeds VM budget”

自闭症网瘾萝莉.ら 提交于 2019-12-21 06:45:17

问题


I made a ViewPager to display images. When I advance some pages I get an java.lang.OutOfMemoryError: bitmap size exceeds VM budget error.

There are more questions about this issue but I did not find the solution (BitMap.Recycle, System.gc() etc). If you have a suggestion or solution please let me know!

The PNG's are 628KB, 478KB, 587KB, 132KB, 139KB, 149KB, 585KB (crash).

If you have an other solution (scroll images like pages) for me let met know!

My code:

package nl.ipear.vngmagazine;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.os.Parcelable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;

public class ShowMagazine2 extends FragmentActivity {
    private ViewPager myPager;
    private MyPagerAdapter myPagerAdapter;

    private static int NUM_PAGES = 15;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.showmagazine);

        myPager = (ViewPager)findViewById(R.id.viewpager1);
        myPagerAdapter = new MyPagerAdapter();
        myPager.setAdapter(myPagerAdapter);

        return;
    }

    private class MyPagerAdapter extends PagerAdapter{
        @Override
        public int getCount() {
            return NUM_PAGES;
        }

        @Override
        public Object instantiateItem(View collection, int position) {      
            String location = Environment.getExternalStorageDirectory() + "/MYData/" + "2012-02/";

            // Inflate and create the view
            LayoutInflater layoutInflater = (LayoutInflater) collection.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = layoutInflater.inflate(R.layout.magazinepageview, null);

            ImageView imageView = (ImageView) view.findViewById(R.id.magazinePageImage);
            String fileName = String.format("%s%s%02d%s", location, "2012-02_Page_", position + 1, ".png");
            Log.v("PNG", fileName);
            imageView.setImageBitmap(BitmapFactory.decodeFile(fileName));

            ((ViewPager) collection).addView(view,0);

            return view;
        }

        @Override
        public void destroyItem(View collection, int position, Object view) {
            ((ViewPager) collection).removeView((View) view);           
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view==((View)object);
        }

        @Override
        public void finishUpdate(View arg0) {}

        @Override
        public void restoreState(Parcelable arg0, ClassLoader arg1) {}

        @Override
        public Parcelable saveState() {
            return null;
        }

        @Override
        public void startUpdate(View arg0) {}   
    }
}

回答1:


It would appear that your ViewPager is loading in the Bitmaps, but not releasing any when you are scrolling through.

I would advise you limit the number of Pages that are available either side of the current viewable Page, which will allow the system to clean up the Bitmaps in the other Pages.

Make sure you are recycling the Bitmaps when your Activity/Fragment is destroyed to help with OOM issues.




回答2:


Try and scale down your Bitmap, it really solves the issue, here is how you do it..

BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile( filename, options );
        options.inJustDecodeBounds = false;
        options.inSampleSize = 2; 

        bitmap = BitmapFactory.decodeFile( filename, options );
        if ( bitmap != null && exact ) {
            bitmap = Bitmap.createScaledBitmap( bitmap, width, height, false );
        }

Adjust sample size to whatever you want it to be e.g. 4, 8 etc




回答3:


Yes follow Mimminito. I advice 2 pages since rendering is equally fast for back and forth for 3 pages.

Now if you need the images without lag and the images are on the internet. Make sure you download it and put inside an internalStorageDevice then reuse it if it exist.

my top answer is maybe incorrect for the issue of a memory leak. This new answer is a probable reason for the memory leak is because of the height and width of the image.

private byte[] resizeImage( byte[] input ) {

    if ( input == null ) {
        return null;
    }

    Bitmap bitmapOrg = BitmapFactory.decodeByteArray(input, 0, input.length);

    if ( bitmapOrg == null ) {
        return null;
    }

    int height = bitmapOrg.getHeight();
    int width = bitmapOrg.getWidth();
    int newHeight = 250;

    float scaleHeight = ((float) newHeight) / height;

    // creates matrix for the manipulation
    Matrix matrix = new Matrix();
    // resize the bit map
    matrix.postScale(scaleHeight, scaleHeight);

    // recreate the new Bitmap
    Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
            width, height, matrix, true);

    bitmapOrg.recycle();

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    resizedBitmap.compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos);            

    resizedBitmap.recycle();

    return bos.toByteArray();            
}       

This top code is for rescalling a bitmap "newHeight" is the new height given to the bitmap.

Now if this doesn't work I am now 100% certain that OP must be overloading the ViewPager with a more views that the android memory can handle. The solution for this is to use a ViewFlipper and use the answer I stated above.




回答4:


Found the answer in here: Android:java.lang.OutOfMemoryError: Failed to allocate a 23970828 byte allocation with 2097152 free bytes and 2MB until OOM

Just add android:hardwareAccelerated="false" and android:largeHeap="true" in your Application tag inside AndroidManifest:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:hardwareAccelerated="false"
        android:largeHeap="true">



回答5:


call System.gc() in oncreate()



来源:https://stackoverflow.com/questions/9772147/viewpager-with-imageview-gives-java-lang-outofmemoryerror-bitmap-size-exceeds

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!