图像适配器泄漏内存

时间:2015-04-24 20:26:25

标签: android android-recyclerview listadapter picasso okhttp

我有一个简单的 ListActivity ,它显示了图像,我在ImageAdapter类的构造函数中为 Picasso Builder 提供了 OkHttpClient

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

效果很好,但在设备的旋转中,我发现堆大小有时会慢慢增长,有时很快,有时会保持稳定。它很少掉落。我是在泄漏内存还是代码中有问题?

修改 我在Picasso的getView()

中打电话后插入了这段代码
if (BuildConfig.DEBUG) {
    Log.i("HEAP SIZE",
    String.valueOf((Runtime.getRuntime().totalMemory() / 1024)
    - (Runtime.getRuntime().freeMemory() / 1024)));
}

我发现在将位图加载到ImageView后,堆大小的增长发生在getView()。 有什么问题?

编辑2 : 试图设置静态ImageAdapter,没有任何改变

编辑3: 尝试使用RecyclerView而不是ListView,行为相同:堆大小不断增长,同时滚动图像列表每onBindViewHolder()步进30-40个字节。设备的旋转堆大小有时会增加甚至2-3兆字节。很少下降。

为什么堆大小缓慢但持续增长?为什么我会在设备旋转后泄漏一些缓存或一些缓存的位图?

更新 尝试了没有构造函数中的代码的适配器(没有new OkHttpClientnew Picasso.Builder),它可以工作, 堆大小现在保持稳定 。那么,使用cookie头管理初始化客户端的正确方法是什么?

结果是: 最后我创建了我的PicassoInstance类,它创建了一个独特的静态Picasso单例并将其设置为Picasso Library的单例。然后我在我的适配器构造函数

中设置它

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

}

1 个答案:

答案 0 :(得分:3)

我无法将其视为过于宽泛,但我建议您took a memory dump并在Eclipse Memory Analizer Tool中仔细查看,以找出哪些引用仍然存在以及由谁执行。

这也是a great write up on it

适配器作为字段泄漏。视图包含包含视图的上下文。碎片甚至是更糟糕的罪犯。 ListActivities是一个应该在很久以前就已被弃用的API1工具。所有这些都非常容易泄漏,但那是Android方式。