Как выпустить память растрового изображения с помощью imageloader в Android?
Я загружаю изображения в виде сетки с сервера. Для этого я использую загрузчик Universal Image. Я использую загрузчик изображений внутри метода getview() адаптера. Он берет URL-адрес изображения из arraylist и загружает изображение с сервера. Изображения могут быть в 100-х годах. Я показываю вид сетки в фрагменте, поэтому для каждого фрагмента есть отдельный вид сетки. Когда я переключаюсь между несколькими фрагментами в течение длительного времени, я больше не получаю ошибку из памяти.
Рекомендуемое решение:
- Отпустите неиспользуемое растровое изображение.
Итак, я загружаю изображения, используя стороннюю библиотеку. Я просто передаю изображение в вызывающей функции, так как я могу освободить растровое изображение?
- Сделать кучу большой истиной в манифесте
Я думаю, что куча памяти динамична, и всякий раз, когда происходит увеличение памяти, сборщик мусора освобождает память.
3.Use UIL/Picasso/Glide, чтобы избежать утечек памяти
4.Code, чтобы освободить память фрагмента onDestroy() method()
private void unbindDrawables(View view)
{
if (view.getBackground() != null)
{
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup && !(view instanceof AdapterView))
{
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
{
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
Я уже использую стороннюю библиотеку.
Вот код для моего класса gridViewAdapter.
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
View view = convertView;
if (view == null)
{
view = inflater.inflate(R.layout.grid_item_photo, parent, false);
holder = new ViewHolder();
holder.imageView = (ImageView) view.findViewById(R.id.imgLoader);
holder.play = (ImageView) view.findViewById(R.id.play);
view.setTag(holder);
}
else
{
holder = (ViewHolder) view.getTag();
}
try{
if(IMAGES_LIST.get(position).getType().equals("video"))
{
holder.play.setVisibility(View.VISIBLE);
}
else
{
holder.play.setVisibility(View.GONE);
}
ImageLoader.getInstance().displayImage(AppConst.BASE_IMAGE_URL+IMAGES_LIST.get(position).getThumbnail(), holder.imageView, options, new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
view.setClickable(true);
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
view.setClickable(true);
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
view.setClickable(false);
}
}, new ImageLoadingProgressListener() {
@Override
public void onProgressUpdate(String imageUri, View view, int current, int total) {
}
});
}catch(Exception e)
{
}
catch(OutOfMemoryError e)
{
}
return view;
}
static class ViewHolder {
ImageView imageView,play;
}
}
Ответы
Ответ 1
-
Похоже на утечку фрагментов - ваш фрагмент остается в памяти со всем содержимым (включая растровое изображение), даже если вызывается onDestroy. Вы можете использовать MAT + Heap dumps, чтобы увидеть, что именно вызывает утечку (там доступно множество руководств). Первыми подозреваемыми должны быть Singletons из классов фрагментов, которые вы передаете "this" из ваших фрагментов. В качестве первого шага я очистил все от вашего фрагмента в onDestroy.
-
Сделайте "SimpleImageLoadingListener()" внутренним статическим классом, который содержит ваш фрагмент как WeakReference - это, вероятно, уменьшит утечку (или, по крайней мере, один из них).
-
Вы должны использовать любой третий ImageLoader в качестве Singleton с одним кешем LRU и одним дисковым кэшем. Здесь вы можете найти несколько хороших (любой лучший сторонний инструмент для кеширования изображения на Android?)
-
"largeHeap" в манифесте не должно быть в вашем уме. Как только у вас будет утечка, вы просто получите большую кучу, чтобы заполнить ее до OOM.
Ответ 2
Yo может удалять кэшированное изображение в кеше памяти. Используйте MemoryCacheUtil
для этого:
MemoryCacheUtils.removeFromCache(imageUrl, imageLoader.getMemoryCache());
И DiscCacheUtils
для удаления discCache
DiscCacheUtils.removeFromCache(url, ImageLoader.getInstance().getDiscCache());
Кроме того, вы можете очистить кэш памяти, используя:
imageLoader.clearMemoryCache();
Кроме того, вы можете контролировать память и диск с ограничениями:
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
.memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024))
.discCache(new UnlimitedDiscCache(cacheDir))
Ответ 3
Может быть, причина в том, что вы просто используете ImageLoader
, создав его экземпляр, а я не знаю о DisplayImageOptions
, что у вас было. Попытайтесь изменить параметры и проверить его. помогите мне загрузить большие изображения в List
.
Попробуйте эти параметры в своем приложении.
DisplayImageOptions imageOptions = new DisplayImageOptions.Builder().showImageForEmptyUri(R.drawable.ic_launcher).showImageOnFail(R.drawable.ic_launcher).resetViewBeforeLoading(true).cacheOnDisk(true).imageScaleType(ImageScaleType.EXACTLY).bitmapConfig(Bitmap.Config.RGB_565).considerExifParams(true).displayer(new FadeInBitmapDisplayer(3000, true, true, false)).build();
Ответ 4
Вы можете попытаться избежать кеша памяти и ограничить кеш диска. Для дальнейших оптимизаций вы можете проверить источник.