Утечка памяти адаптера изображения
у меня простой ListActivity это показывает изображения, и я inizialize мой OkHttpClient на Пикассо Строитель в конструкторе класса ImageAdapter:
picassoClient = new OkHttpClient();
picassoClient.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain
.request()
.newBuilder()
.addHeader("Cookie","xyz")
.build();
return chain.proceed(newRequest);
}
});
new Picasso.Builder(context).downloader(new OkHttpDownloader(picassoClient)).build();
затем в getView()
Я использую Picasso для загрузки изображений в ImageView:
Picasso.with(context).load(xyzUrl).fit().centerCrop().into(vImage);
он работает хорошо, но при вращении устройства я вижу, что размер "кучи" иногда медленно растет, иногда быстро и иногда остается стабильным. Только изредка капли. У меня утечка памяти или что-то не так в коде?
EDIT:
Я вставил этот код после звонка Пикассо в getView()
if (BuildConfig.DEBUG) {
Log.i("HEAP SIZE",
String.valueOf((Runtime.getRuntime().totalMemory() / 1024)
- (Runtime.getRuntime().freeMemory() / 1024)));
}
и я обнаружил, что рост размера кучи происходит в getView()
после загрузки растрового изображения в ImageView.
Что случилось?
правка 2: пытался установить статический ImageAdapter, ничего не меняется
EDIT 3:
пробовал с RecyclerView вместо ListView, такое же поведение: размер кучи непрерывно растет при прокрутке списка изображений, шагая на 30-40 байт при каждом onBindViewHolder()
. После вращения устройства размер кучи увеличивается иногда даже на 2-3 Мбайт. Редко падает.
почему размер кучи медленно, но непрерывно растет и почему я пропускаю некоторый кэш или некоторые кэшированные растровые изображения после вращения устройства?
обновление:
пробовал адаптер без кода в конструкторе (то есть без new OkHttpClient
и new Picasso.Builder
), он работает и размер кучи теперь падает, оставаясь стабильным. Тогда как правильно инициализировать клиента с помощью управления заголовками cookies?
результат: наконец, я создал свой класс PicassoInstance, который создает уникальный статический синглтон Пикассо и устанавливает его как синглтон библиотеки Пикассо. Затем я установил его в своем конструкторе адаптера
PicassoInstance.setPicassoSingleton(context);
он работает хорошо, и это правильный путь I надеяться.
public class PicassoInstance {
private static Picasso myPicassoInstance = null;
public static void setPicassoSingleton(Context context) {
if (myPicassoInstance == null) {
myPicassoInstance = createMyPicassoInstance(context);
Picasso.setSingletonInstance(myPicassoInstance);
if (BuildConfig.DEBUG) {
Log.i("PICASSO INSTANCE", "CREATED");
}
}
}
private static Picasso createMyPicassoInstance(Context context) {
OkHttpClient myOkHttpClient = new OkHttpClient();
myOkHttpClient.interceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Cookie", "xyz").build();
if (BuildConfig.DEBUG) {
Log.i("ON INTERCEPT", "COOKIE ADDED");
}
return chain.proceed(newRequest);
}
});
return new Picasso.Builder(context).downloader(
new OkHttpDownloader(myOkHttpClient)).build();
}
}
2 ответов
экземпляр picasso возвращается из PicassoBuilder.build () должен быть одноэлементным, и когда вам нужно использовать picasso во всем приложении, вы должны получить доступ к этому одноэлементному, а не Пикассо.с... вы должны получить доступ
YourClass.getMyPicassoSingleton().with...
в противном случае вы держите отдельные кэши и т. д. Для этих экземпляров picasso
edit: как я отметил ниже, вы также можете вызвать
picasso.setSingletonInstance(myPicasso);
справа, где вы вызываете метод сборки выше, который также решит ваша проблема, не держась за синглтона самостоятельно. это, вероятно, более чистое решение
Я не могу закрыть его, как слишком широкий, но я бы рекомендовал вам взял дамп памяти и дал ему длинный твердый взгляд в Eclipse Memory Analizer Tool чтобы найти, какие ссылки все еще сохраняются в живых и кто.
Это тоже отличная запись на нем.
адаптеры как поля протекают. Представления содержат контекст, содержащий представления. А осколки-еще хуже. ListActivities были инструментом API1, который должен был быть давно устарел. Все очень подвержены утечке, но это путь Android.