ViewPager с ImageView выдает «java.lang.OutOfMemoryError: размер растрового изображения превышает бюджет виртуальной машины» - PullRequest
2 голосов
/ 19 марта 2012

Я сделал ViewPager для отображения изображений.Когда я продвигаю некоторые страницы, я получаю ошибку java.lang.OutOfMemoryError: bitmap size exceeds VM budget.

Есть еще вопросы по этой проблеме, но я не нашел решения (BitMap.Recycle, System.gc() и т. Д.).Если у вас есть предложение или решение, сообщите мне!

PNG: 628 КБ, 478 КБ, 587 КБ, 132 КБ, 139 КБ, 149 КБ, 585 КБ (сбой).

Если у вас есть другое решение(прокручивайте изображения, как страницы), дайте мне знать!

Мой код:

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) {}   
    }
}

Ответы [ 5 ]

1 голос
/ 09 декабря 2016

Нашел ответ здесь: Android: java.lang.OutOfMemoryError: Не удалось выделить 23970828 байт с 2097152 свободными байтами и 2 МБ до OOM

Просто добавьте android:hardwareAccelerated="false" иandroid:largeHeap="true" в теге приложения внутри 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">
1 голос
/ 19 марта 2012

Да, следуй за Мимминито.Я советую 2 страницы, так как рендеринг одинаково быстр для перемотки вперед и назад для 3 страниц.

Теперь, если вам нужны изображения без задержек и изображения в Интернете.Убедитесь, что вы загрузили его и поместили в internalStorageDevice, а затем повторно использовали его, если он существует.

Мой главный ответ может быть неверным для проблемы утечки памяти.Этот новый ответ является вероятной причиной утечки памяти из-за высоты и ширины изображения.

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

Этот верхний код предназначен для повторного вызова растрового изображения «newHeight» - это новая высота, присваиваемая растровому изображению.

Теперь, если это не сработает, я теперь на 100% уверен, что OP должен перегружать ViewPager с большим количеством представлений, которые может обрабатывать память Android.Решением для этого является использование ViewFlipper и ответ, который я изложил выше.

1 голос
/ 19 марта 2012

Попробуйте уменьшить изображение, оно действительно решает проблему, вот как вы это делаете.

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

Отрегулируйте размер выборки так, как вы хотите, например. 4, 8 и т. Д.

1 голос
/ 19 марта 2012

Может показаться, что ваш ViewPager загружается в растровые изображения, но не выпускает их при прокрутке.

Я бы посоветовал вам ограничить количество страниц, доступных по обе стороны от текущей просматриваемой страницы, что позволит системе очищать растровые изображения на других страницах.

Убедитесь, что вы перерабатываете битовые карты, когда ваша деятельность / фрагмент уничтожены, чтобы помочь с проблемами OOM.

0 голосов
/ 05 мая 2014

вызов System.gc () в oncreate ()

...