Утечка памяти адаптера изображения
у меня простой 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.
