У меня есть RecyclerView
, представляющий несколько изображений, используя Picasso
. После прокрутки некоторое время вверх и вниз, приложение запускается из памяти с сообщениями, как это:Пикассо: из памяти
E/dalvikvm-heap﹕ Out of memory on a 3053072-byte allocation.
I/dalvikvm﹕ "Picasso-/wp-content/uploads/2013/12/DSC_0972Small.jpg" prio=5 tid=19 RUNNABLE
I/dalvikvm﹕ | group="main" sCount=0 dsCount=0 obj=0x42822a50 self=0x59898998
I/dalvikvm﹕ | sysTid=25347 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=1500612752
I/dalvikvm﹕ | state=R schedstat=(10373925093 843291977 45448) utm=880 stm=157 core=3
I/dalvikvm﹕ at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
I/dalvikvm﹕ at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:623)
I/dalvikvm﹕ at com.squareup.picasso.BitmapHunter.decodeStream(BitmapHunter.java:142)
I/dalvikvm﹕ at com.squareup.picasso.BitmapHunter.hunt(BitmapHunter.java:217)
I/dalvikvm﹕ at com.squareup.picasso.BitmapHunter.run(BitmapHunter.java:159)
I/dalvikvm﹕ at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390)
I/dalvikvm﹕ at java.util.concurrent.FutureTask.run(FutureTask.java:234)
I/dalvikvm﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
I/dalvikvm﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
I/dalvikvm﹕ at java.lang.Thread.run(Thread.java:841)
I/dalvikvm﹕ at com.squareup.picasso.Utils$PicassoThread.run(Utils.java:411)
I/dalvikvm﹕ [ 08-10 18:48:35.519 25218:25347 D/skia ]
--- decoder->decode returned false
Вещи, которые я внимание при отладке:
- При установке приложения на телефон или виртуального устройства, изображения загружаются по сети, как и должно быть. Это видно по красному треугольнику в верхнем левом углу изображения.
- При прокрутке, чтобы изображения перезагружались, они извлекаются с диска. Это видно по синему треугольнику в верхнем левом углу изображения.
- При прокрутке некоторых изображений некоторые изображения загружаются из памяти, как видно из зеленого треугольника в верхнем левом углу.
- После прокрутки еще больше возникает исключение из памяти и прекращается загрузка. На изображениях, которые в настоящее время не хранятся в памяти, отображается только изображение-заполнитель, а в памяти - зеленый треугольник.
Here - образец изображения. Он довольно большой, но я использую fit()
, чтобы уменьшить объем памяти в приложении.
Так что мои вопросы:
- не должны изображения быть перезагружен с диска, когда кэш-память заполнена?
- Изображения слишком большие? Сколько памяти может быть ожидать, скажем, 0,5 МБ изображения, потреблять при декодировании?
- Что-нибудь не в порядке/необычного в моем коде ниже?
Настройка статического экземпляра Picasso при создании Activity
:
private void setupPicasso()
{
Cache diskCache = new Cache(getDir("foo", Context.MODE_PRIVATE), 100000000);
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setCache(diskCache);
Picasso picasso = new Picasso.Builder(this)
.memoryCache(new LruCache(100000000)) // Maybe something fishy here?
.downloader(new OkHttpDownloader(okHttpClient))
.build();
picasso.setIndicatorsEnabled(true); // For debugging
Picasso.setSingletonInstance(picasso);
}
Используя статический экземпляр Пикассо в моем RecyclerView.Adapter
:
@Override
public void onBindViewHolder(RecipeViewHolder recipeViewHolder, int position)
{
Picasso.with(mMiasMatActivity)
.load(mRecipes.getImage(position))
.placeholder(R.drawable.picasso_placeholder)
.fit()
.centerCrop()
.into(recipeViewHolder.recipeImage); // recipeImage is an ImageView
// More...
}
ImageView
в XML файл:
<ImageView
android:id="@+id/mm_recipe_item_recipe_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:paddingBottom="2dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:clickable="true"
/>
Update
кажется, что прокрутка RecyclerView
непрерывно делает увеличение выделения памяти на неопределенный срок. Я сделал тест RecyclerView
, снятый в соответствии с official documentation, используя одно изображение для 200 CardView
s с ImageView
, но проблема не устранена. Большая часть изображений загружается из памяти (зеленая), а прокрутка плавная, но примерно каждая десятая ImageView
загружает изображение с диска (синий). Когда изображение загружается с диска, выполняется распределение памяти, тем самым увеличивая распределение в куче и, таким образом, кучу.
Я попытался удалить свою собственную настройку глобального экземпляра Picasso
и использовать по умолчанию вместо этого, но проблемы одинаковы.
Я проверил монитор Android-устройств, см. Изображение ниже. Это для Галактики S3. Каждое из распределений, выполняемых при загрузке изображения с диска, можно увидеть справа в разделе «Счет подсчета для каждого размера». Размер немного отличается для каждого размещения изображения, что тоже странно. Нажатие кнопки «Причина GB» делает самое правильное выделение 4,7 МБ.
поведение является одинаковым для виртуальных устройств. На рисунке ниже показано его для AVS Nexus 5. Также здесь наибольшее распределение (10,6 МБ) уходит при нажатии «Причина GB».
Кроме того, здесь есть изображения мест выделения памяти и потоки от монитора Android устройств. Повторные выделения выполняются в потоках Picasso
, тогда как один удаленный с Cause GB
выполняется в основном потоке.
У меня такая же проблема. Даже при наличии только 25 единиц ресайклеров, если я постоянно прокручиваю вверх и вниз, он выходит из строя с исключением из памяти. – Zapnologica