OutOfMemoryError: размер растрового изображения превышает бюджет виртуальной машины - PullRequest
2 голосов
/ 14 апреля 2011

Извините, это похоже на повторный вопрос, НО я думаю, что не подпадаю под какую-либо из уже опубликованных рекомендаций.

В моем приложении есть максимум 20 изображений.Проигрывая некоторое время назад и вперед, я получаю OutOfMemoryError.

Странно то, что у меня нет статических ссылок, и я искал возможные утечки памяти, я могу заверить, что япока не нашел ни одного.

В любом случае, 20 изображений (PNG в среднем 100 КБ) не такие уж и большие.И я реализовал кеш представления, держатели SoftReference для растровых изображений и т. Д.

Достаточно ли в среднем 20 PNG-изображений размером 100 КБ, чтобы убить мое приложение?шутки в сторону?как я могу избавиться от этого?Я также следовал этому великому посту

http://blog.jteam.nl/2009/09/17/exploring-the-world-of-android-part-2/

Есть еще идеи?

Это ImageCache:

public class AsyncImageLoader {

    private final String TAG = getClass().getSimpleName();
    private Context mContext;
    private HashMap<String, SoftReference<Bitmap>> mImageCache;

    public AsyncImageLoader(Context context) {
        mContext = context;
            mImageCache = new HashMap<String, SoftReference<Bitmap>>();
    }

    public Bitmap loadImage(final String identifier, final String imagePath, final ImageCallback imageCallback) {

        if (mImageCache.containsKey(imagePath)) {
            SoftReference<Bitmap> softReference = mImageCache.get(imagePath);
            Bitmap bitmap = softReference.get();
            if (bitmap != null) {
                Log.i(TAG, "Retrieving image from cache: " + imagePath);
                return bitmap;
            }
        }

        final Handler handler = new Handler() {
            @Override
            public void handleMessage(Message message) {
                imageCallback.imageLoaded((Bitmap) message.obj, imagePath, identifier);
            }
        };

        new Thread() {

            @Override
            public void run() {
                Bitmap bitmap = loadImageFromPath(imagePath);
                mImageCache.put(imagePath, new SoftReference<Bitmap>(bitmap));
                Message message = handler.obtainMessage(0, bitmap);
                handler.sendMessage(message);
            }

        }.start();

        return null;
    }

    public Bitmap loadImageFromPath(String path) {

        if(!GeneralUtilities.isEmpty(path)) {
            Log.i(TAG, "Loading image: " + path);
            InputStream imageInputStream = null;

            try {               
                final AssetManager assetManager = mContext.getResources().getAssets(); 
                imageInputStream = assetManager.open(path);

                Bitmap bitmap = GeneralUtilities.decodeFile(imageInputStream);

                imageInputStream.close();

                return bitmap;
            } catch (final IOException e) {
                Log.e(TAG, e.getMessage());
            }        
        }

        return null;
    }

    public interface ImageCallback {
        public void imageLoaded(Bitmap imageBitmap, String imagePath, String identifier);
    }
}

и методGeneralUtilities.decodeFile - это:

public static Bitmap decodeFile(InputStream is){
        //Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(is, null, o);

        //The new size we want to scale to
        final int REQUIRED_SIZE=140;

        //Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;

        while(true) {
            if(width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
                break;
            width_tmp /= 2;
            height_tmp /= 2;

            scale *= 2;
        }

        //Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(is, null, o2);  
      }

И в getView ArrayAdapter у меня есть что-то вроде этого:

final ImageView itemImage = cache.getHistoryImage();        
        //final ImageView itemFrame = cache.getFrame();

        String filename = item.getFilename().trim();

        itemImage.setTag("front_" + filename);

        Bitmap cachedImage = mAsyncImageLoader.loadImage("front_" + filename, filename, new ImageCallback() {

            public void imageLoaded(Bitmap imageBitmap, String imagePath, String identifier) {

                ImageView imageViewByTag = (ImageView) mGallery.findViewWithTag(identifier);
                if (imageViewByTag != null) {
                    imageViewByTag.setImageBitmap(imageBitmap);
                }
            }
        });

        itemImage.setImageBitmap(cachedImage);

1 Ответ

2 голосов
/ 14 апреля 2011

Кажется, что есть ошибка в платформе Android, хотя Google, похоже, это отрицает.

Читали ли вы номер 8488?

http://code.google.com/p/android/issues/detail?id=8488

IЯ не уверен, относится ли это к вашему коду - но вы можете попробовать рекомендации перед установкой / обновлением изображения в ImageView.

По сути, это сводится к вызову Bitmap.recycle (), обнуляя ссылки (вероятно, не относящиеся к делу).в вашем случае) и явным вызовом вызова System.gc ().

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

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