КОТ++
Прикладное программирование
Системное программирование
Программирование микроконтроллеров

Программирование — это не наука, а ремесло. (c) Ричард Столлман

Поиск по тегам

Опубликовано
Комментарии 1

Используете много картинок в своём андроид приложении? И при этом бывает вылетает ошибка OutOfMemory связанная с показом картинок? В таком случае этот пост для вас.

Сам недавно столкнулся с такой проблемой, поэтому в этой статье могу предложить некоторое решение. В моём приложении картинки загружались с сервера и отображались сразу в большом количестве на экране смартфона. И когда хип переполнялся из-за большого количества картинок в памяти приложение падало, падение можно обойти, но картинки всё равно уже не отображаются там где надо. Самое очевидное решение это подгружать только те картинки, которые пользователь может просматривать в данный момент. Но определить какие из ImageView сейчас находятся в видимости пользователя, а какие нет тоже не простая задача. А ведь охото сделать простое и быстрое решение.

На stackoverflow.com предлагали ужимать картинки, а потом выводить на экран. В принципе неплохое решение, но чтоб отобразить сразу много картинок нужно применить 7/10 шакалов ко всем картинкам.

Также видел совет по увеличению хипа для приложения, прописать в манифесте:

android:largeHeap=«true»

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

Остаётся заюзать какую-нибудь библиотеку для подгрузки изображений из инета. На слуху у меня две таких либы: Picasso и Android-Universal-Image-Loader. Мне по некоторым причинам больше приглянулась вторая либа. Её то и попробуем использовать. Подключим в свой проект и пропишем код инициализации. Мне наиболее оптимальным кажется такой вариант (некоторые параметры были найден уже не вспомню на каком форуме):

        Executor downloadExecutor = Executors.newFixedThreadPool(5);
        Executor cachedExecutor = Executors.newSingleThreadExecutor();

ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); int memClass = am.getMemoryClass(); final int memoryCacheSize = 1024 * 1024 * memClass / 8; options = new DisplayImageOptions.Builder() .showImageOnLoading(R.drawable.ic_stub_image) .bitmapConfig(Bitmap.Config.RGB_565) .imageScaleType(ImageScaleType.IN_SAMPLE_INT) .cacheInMemory(true) .cacheOnDisc(true) .build(); File cacheDir = StorageUtils.getCacheDirectory(this); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext()) .taskExecutor(downloadExecutor) .taskExecutorForCachedImages(cachedExecutor) .memoryCache(new UsingFreqLimitedMemoryCache(memoryCacheSize)) // 2 Mb .diskCache(new LimitedAgeDiskCache(cacheDir, 52428800)) .imageDownloader(new BaseImageDownloader(this, 5 * 1000, 30 * 1000)) .defaultDisplayImageOptions(options) .build(); ImageLoader.getInstance().init(config);

Далее скачиваем и показываем картинку:

ImageLoader.getInstance().displayImage(imageUrl, imageView, MainActivity.options);

Но позже выясняется, что такой вариант особо не спасает. В логах у нас также будет OutOfMemory. А что если грузить сначала превьюшки для изображений (т.е. сжатые маленькие картинки), а если юзер просматривает картинку полностью, то в этот момент подгружать уже оригинал? Попробуем (код для подгрузки превьюхи):

ImageLoader.getInstance().displayImage(imageUrl, imageView, new ImageSize(80, 80));

Для подгрузки оригиналов воспользуйтесь кодом чуть выше. Проверяем, работает!

Данное решение не оптимизирует работу приложения так, как хотелось бы одержимому перфекционисту, но вполне побеждает OutOfMemory!

Теги , ,
Автор