Подтвердить что ты не робот

Проникающая память адаптера изображения

У меня есть простая ListActivity, которая показывает изображения, и я инициализирую свой OkHttpClient для Picasso Builder в конструкторе класса 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. Что не так?

EDIT 2: попытался установить статический ImageAdapter, ничего не изменилось

ИЗМЕНИТЬ 3: попробовал с RecyclerView вместо ListView, такое же поведение: размер кучи растет непрерывно, при прокрутке списка изображений с шагом 30-40 байт на каждом onBindViewHolder(). После вращения устройства размер кучи увеличивается, иногда даже на 2-3 Мбайт. Редко он падает.

Почему размер кучи медленно, но постоянно растет и почему я пропускаю кеш или некоторые кэшированные растровые изображения после поворота устройства?

UPDATE: попробовал адаптер без кода в конструкторе (без new OkHttpClient и new Picasso.Builder), он работает, и размер кучи теперь падает и остается стабильным. Затем, каков правильный способ инициализации клиента с помощью управления заголовками файлов?

развязка: наконец, я создал свой класс PicassoInstance, который создает уникальный статический синтаксис Picasso и устанавливает его как одноэлементную библиотеку Picasso. Затем я установил его в свой конструктор адаптера

PicassoInstance.setPicassoSingleton(context);

Это хорошо работает, и я надеюсь, что это правильный способ.

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();
}

}

4b9b3361

Ответ 1

Экземпляр picasso, возвращаемый из PicassoBuilder.build(), должен быть одиночным, и когда вам нужно использовать picasso во всем приложении, вы должны получить доступ к этому синглтону, а не Picasso.with... вы должны получить доступ к

YourClass.getMyPicassoSingleton().with...

В противном случае вы сохраняете отдельные кеши и т.д. для этих экземпляров picasso

изменить: как я заметил ниже, вы также можете позвонить

picasso.setSingletonInstance(myPicasso);

прямо там, где вы вызываете метод сборки выше, что также решит вашу проблему, не удерживая сам синглтон. это, вероятно, более чистое решение

Ответ 2

Я не могу закрыть его слишком широко, но я бы порекомендовал вам взять дамп памяти и дал ему длинный жесткий взгляд в Eclipse Memory Analizer Tool, чтобы найти, какие ссылки все еще поддерживаются и кем.

Это также отличная запись на нем.

Адаптеры как поля являются негерметичными. Представления содержат контекст, который содержит представления. И фрагменты еще хуже, чем обидчики. ListActivities - это инструмент API1, который давно должен был быть устаревшим. Все очень склонны к утечке, но это способ Android.