Просмотр пейджера с универсальным загрузчиком изображений
Я не уверен, что ViewPager с Universal Image Loader может/должен использоваться в качестве альтернативы для галереи, такой как интерфейс, так как я столкнулся с ошибкой "Недостаточно памяти" при загрузке изображений с SD-карты и просмотре их в полноэкранном режиме Режим. Независимо от того, какой номер, он отлично работает с GridView, но при просмотре изображений в представлении Pager каждый битмап продолжает есть много памяти и после 10 или около того изображений он выдает ошибку из памяти.
Я видел почти все вопросы, которые были размещены здесь, связанные с ошибкой "Недостаточно памяти" при работе с Universal Image Loader, и в каждом из них в качестве причины была ошибка конфигурации.
Я не знаю, использую ли я неправильные конфигурации или что, но я потратил много времени на это и застрял, любая помощь/совет будут оценены.
Конфигурации для ImageLoader:
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.memoryCache(new WeakMemoryCache())
.denyCacheImageMultipleSizesInMemory()
.discCacheFileNameGenerator(new Md5FileNameGenerator())
.imageDownloader(new ExtendedImageDownloader(getApplicationContext()))
.tasksProcessingOrder(QueueProcessingType.LIFO)
// .enableLogging() // Not necessary in common
.build();
Параметры изображения:
options = new DisplayImageOptions.Builder()
.showImageForEmptyUri(R.drawable.image_for_empty_url)
.resetViewBeforeLoading()
.imageScaleType(ImageScaleType.IN_SAMPLE_INT)
.bitmapConfig(Bitmap.Config.RGB_565)
.displayer(new FadeInBitmapDisplayer(300))
.build();
Я использую пример проекта, который был предоставлен в библиотеке, но эти настройки не будут работать, он просто сработает через некоторое время. Я предполагаю, что существует конкретный обратный вызов, когда мне приходится перерабатывать растровые изображения из представлений, которые не видны.
EDIT: я знаю, что это утечка памяти. Представления, которые не видны, уничтожаются, когда они должны быть, но память не освобождается, как следует. Это реализация обратного вызова destroyItem, следуя советам, приведенным в разных вопросах, но все же не может найти утечку памяти.
@Override
public void destroyItem(View container, int position, Object object) {
// ((ViewPager) container).removeView((View) object);
Log.d("DESTROY", "destroying view at position " + position);
View view = (View)object;
((ViewPager) container).removeView(view);
view = null;
}
Ответы
Ответ 1
Попробуйте применить следующие предложения:
- Используйте
ImageScaleType.EXACTLY
- Включить кеширование на диске (в параметрах отображения).
- Наконец, попробуйте использовать
.discCacheExtraOptions(maxImageWidthForDiscCache, maxImageHeightForDiscCache, CompressFormat.PNG, 0);
Ответ 2
Вероятно, это не лучшая реализация, но для меня это работало. Удаление ImageViews недостаточно, поэтому я решил переработать растровые изображения в 'destroyItem':
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
View view = (View) object;
ImageView imageView = (ImageView) view.findViewById(R.id.image);
if (imageView != null) {
Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
bitmap.recycle();
bitmap = null;
}
((ViewPager) container).removeView(view);
view = null;
}
Это не очищает последние 3 активные страницы, когда вы покидаете активность, хотя я надеюсь, что GC позаботится о них.
Ответ 3
Просто опубликуйте это, потому что этот вопрос появляется в Google при поиске UIL и ООП. У меня были проблемы с ООП независимо от того, какая конфигурация, в чем были решены все мои проблемы: два класса RecyclingImageView
и RecyclingBitmapDrawable
из этот образец проекта.
Ответ 4
Я также использовал одну и ту же библиотеку и имел ту же ошибку. В качестве решения я создал sparseArray для хранения экземпляров photoView. И используйте его вот так:
private SparseArray<PhotoView> photoViewHolder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
photoViewHolder = new SparseArray<PhotoView>();
...
}
private class GalleryPagerAdapter extends PagerAdapter {
@Override
public View instantiateItem(ViewGroup container, int position) {
PhotoView photoView = new PhotoView(container.getContext());
ImageHolder holder = new ImageHolder();
holder.position = position;
holder.loaded = false;
photoView.setTag(holder);
photoViewHolder.put(position, photoView);
// I used LazyList loading
loader.DisplayImage(items.get(position), photoView);
// Now just add PhotoView to ViewPager and return it
container.addView(photoView, LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
return photoView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
photoViewHolder.remove(position);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}
И для обработки прослушивателя viewPager:
pager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int position) {
}
@Override
public void onPageScrolled(int position, float arg1, int arg2) {
}
@Override
public void onPageSelected(int position) {
if(photoViewHolder.get(position) != null) {
ImageHolder holder = (ImageHolder)photoViewHolder.get(position).getTag();
// Do something...
}
}
});
Надеюсь, что это поможет...
Ответ 5
Я использовал реализацию kutothe на странице github.
Ответ 6
У меня была эта проблема, когда просто устанавливали Uri на ImageView
, используя: iv.setImageURI(Uri.fromFile(imgFile));
У меня была такая же проблема с Universal Image Loader, и я даже искал другие Image Loaders там, и нашел еще один хороший, получивший название Picasso ", но у него также была та же проблема.
Так что сработало для меня использование GestureImageView
и установка gesture-image:recycle
в true через XML и загрузить изображения со следующим кодом
Drawable yourDrawable = null;
try {
InputStream inputStream = getActivity().getContentResolver().openInputStream(Uri.fromFile(img));
yourDrawable = Drawable.createFromStream(inputStream, Uri.fromFile(img).toString() );
inputStream.close();
} catch (FileNotFoundException e) {
yourDrawable = getResources().getDrawable(R.drawable.ic_launcher);
} catch (IOException e) {
e.printStackTrace();
}
if (yourDrawable != null)
iv.setImageDrawable(yourDrawable);
причина, по которой он сбой, и сообщение об ошибке OOM заключается в том, что растровые изображения не перерабатываются, когда изображение больше не отображается на экране, поэтому происходит утечка памяти.
Если есть другой способ переработать растровое изображение в обычном ImageView
, это будет лучшим решением.
Надеюсь, я помог.
Ответ 7
Я знаю это поздно, но, может быть, мой ответ сэкономит время. Спустя несколько часов и часов, пытаясь решить эту проблему (почти каждый ответ, найденный при переполнении стека), я, наконец, решил это с помощью библиотеки изображений Fresco. Это lib, написанный Facebook, и главная цель - эффективно использовать память. Это действительно здорово, и мой Out Of Memory Error исчез. Я настоятельно рекомендую использовать его.
http://frescolib.org/