图像适配器泄漏内存

GPa*_*ack 19 android listadapter picasso okhttp android-recyclerview

我有一个简单的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();
Run Code Online (Sandbox Code Playgroud)

然后在getView()我使用Picasso在ImageView中加载图像:

Picasso.with(context).load(xyzUrl).fit().centerCrop().into(vImage);
Run Code Online (Sandbox Code Playgroud)

它运行良好,但在设备的旋转中,我看到堆大小有时会慢慢增长,有时很快,有时会保持稳定.它很少掉落.我是在泄漏内存还是在代码中出现了问题?

编辑: 我在Picasso的电话中插入了这段代码getView()

if (BuildConfig.DEBUG) {
    Log.i("HEAP SIZE",
    String.valueOf((Runtime.getRuntime().totalMemory() / 1024)
    - (Runtime.getRuntime().freeMemory() / 1024)));
}
Run Code Online (Sandbox Code Playgroud)

我发现堆大小的增长发生在getView()后加载位图到ImageView中.怎么了?

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

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

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

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

UPSHOT: 最后我创建了我的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();
}
Run Code Online (Sandbox Code Playgroud)

}

dab*_*uck 7

从PicassoBuilder.build()返回的picasso实例应该是一个单例,当你需要在整个应用程序中使用picasso时,你应该访问那个单例,而不是Picasso.with ...你应该访问

YourClass.getMyPicassoSingleton().with...
Run Code Online (Sandbox Code Playgroud)

否则,你会为那些毕加索实例保留单独的缓存等

编辑:正如我在下面提到的,你也可以打电话

picasso.setSingletonInstance(myPicasso);
Run Code Online (Sandbox Code Playgroud)

在你调用上面的构建方法的地方,这也可以解决你的问题而不需要自己保留单例.这可能是一个更清洁的解决方案

  • 我认为在引擎盖下,毕加索也会这样做并且每次都会给你一个"单身人士" (2认同)