Okhttp: WARNING: A connection to https://... was leaked. Did you forget to close a response body?

Created on 3 Feb 2016  ·  61Comments  ·  Source: square/okhttp

Version:
com.squareup.okhttp3:okhttp:3.0.1

Log message:

<timestamp> okhttp3.ConnectionPool pruneAndGetAllocationCount
WARNING: A connection to https://... was leaked. Did you forget to close a response body?

Code:

private String get(final String url) {
    String res = null;
    try {
        final Request req = new Request.Builder().url(url).get().build();
        final Response resp = ok.newCall(req).execute();
        final int code = resp.code();
        if (code == 200) {
            final ResponseBody body = resp.body();
            res = body.string();
            body.close(); // even this doesn't work!
        }
    }
    catch (final Throwable th) {
        System.out.println(th.getMessage());
    }
    return res;
}

Most helpful comment

That code does not close the body when the code is not 200. Use a try/finally with body.close() in the finally block.

All 61 comments

That code does not close the body when the code is not 200. Use a try/finally with body.close() in the finally block.

  1. If the code is not 200 -> there's no call to resp.body() -> there's no body -> there's nothing to close. Is it so?
  2. I thought I don't have to call body.close() at all! I just put it there for an experiment. Do I have to call body.close() everytime?

Everytime.

Ok, it's called eveytime, as you see in my code. But I still get that warning.

I get that warning from time to time. I make like 100 calls and get 1 warning. 99 calls are ok.

Code is the same in all 100 calls.

Your code calls it only in the success case, which is not every time.

If the code is not 200 -> there's no call to resp.body() -> there's no body -> there's nothing to close.

This is false.

I commented each valuable line.

private String get(final String url) {
    String res = null;
    try {
        final Request req = new Request.Builder().url(url).get().build();
        final Response resp = ok.newCall(req).execute();
        final int code = resp.code(); // can be any value
        if (code == 200) {
            final ResponseBody body = resp.body(); // body exists, I have to close it
            res = body.string(); // 
            body.close(); // I close it explicitly
        }
        // if code was not 200 -> there's no body (opened to be closed) -> there's nothing to close
        // What am I supposed to close?
    }
    catch (final Throwable th) {
        System.out.println(th.getMessage());
    }
    return res;
}

You have to close the body. Just because you are not calling the method doesn't mean the body is not there.

ResponseBody body = resp.body();
try {
  ...
} finally {
 body.close();
}

Ignoring this fact, the code you showed doesn't cover the case when body.string() throws either.

What about this case:

private String get(final String url) {
    String res = null;
    try {
        final Request req = new Request.Builder().url(url).get().build();
        final Response resp = ok.newCall(req).execute();
        final int code = resp.code(); // can be any value
        System.out.println(code); // I don't want to get body from resp, just print the code
        // There's no body, there's nothing opened, there's nothing to close
        // Do I have to call resp.body().close() anyway in finally block or something like that?
    }
    catch (final Throwable th) {
        System.out.println(th.getMessage());
    }
    return res;
}

there's nothing opened

The connection is open. That's where the code came from. You always have to close the body. There's nothing ambiguous about "always".

https://github.com/square/okhttp/issues/2158#issuecomment-167283937
"Most call body().string() which closes it for you."
How is that?

Calling string() closes the body, yes.

So, just to read the code of the get response, I have to write something like:

private void printCode(final String url) {
    Response resp = null;
    try {
        final Request req = new Request.Builder().url(url).get().build();
        resp = ok.newCall(req).execute();
        final int code = resp.code();
        System.out.println(code);
    }
    catch (final Throwable th) {
        System.out.println(th.getMessage());
    }
    finally {
        if (resp != null) {
            try {
                resp.body().close();
            }
            catch (final Throwable th) {
                System.out.println(th.getMessage());
            }
        }
    }
}

Nope

Request req = new Request.Builder().url(url).build();
Response res = ok.newCall(req).execute();
System.out.println(resp.code());
res.body().close();

The question was answered earlier, so I'm closing the issue.

So this is the right one:

private String get(final String url) {
    String res = null;
    try {
        final Request req = new Request.Builder().url(url).get().build();
        final Response resp = ok.newCall(req).execute();
        final int code = resp.code();
        if (code == 200) {
            try (ResponseBody body = resp.body()) {
                res = body.string();
            }
        }
    }
    catch (final Throwable th) {
        System.out.println(th.getMessage());
    }
    return res;
}

That code doesn't close the body in non-200 cases.

That's a bit weird thing to remember, to close something you didn't explicitly open :)

You opened it by making the request. Calling body just accesses something that already exists.

That's the right (ugly) one:

private String get(final String url) {
    String res = null;
    try {
        final Request req = new Request.Builder().url(url).get().build();
        final Response resp = ok.newCall(req).execute();
        final int code = resp.code();
        try (final ResponseBody body = resp.body()) {
            if (code == 200) {
                res = body.string();
            }
            else {
                log.warn("code: " + code);
            }
        }
    }
    catch (final Throwable th) {
        log.warn(th.getMessage());
    }
    return res;
}

So if I call body.string() and it throws exception, body remains opened and has to be closed, right?

I mean body.string() closes body implicitly only in positive case with no exceptions, and remains it opened if the exception is thrown, right?

I think body.string() automatically closed.

There is like

if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

so you don't need 200 checks.

@iNoles If that was the case, the first version of the code wouldn't cause warnings, I guess.

body.string() which closes body anyway, if there's or there's no exception - that would be a nice cute API :)

The first version doesn't close in the non-200 case.

string() always closes. You can look at the source.

On Wed, Feb 3, 2016, 6:53 PM bxqgit [email protected] wrote:

body.string() which closes body anyway, if there's or there's no exception

  • that would be a nice cute API :)


Reply to this email directly or view it on GitHub
https://github.com/square/okhttp/issues/2311#issuecomment-179538063.

@bxqgit

private String get(final String url) {
    String res = null;
    try {
        final Request req = new Request.Builder().url(url).get().build();
        final Response response = ok.newCall(req).execute();
        if (!response.isSuccessful()) {
            log.warn(new IOException("Unexpected code " + response));
        } else {
            res = response.body().string();
        }
    catch (Throwable th) {
        log.warn(th.getMessage());
    }
    return res;
}

@JakeWharton ok, then this should work:

private String get(final String url) {
    String res = null;
    try {
        final Request req = new Request.Builder().url(url).get().build();
        final Response resp = ok.newCall(req).execute();
        res = resp.body().string();
        final int code = resp.code();
        if (code != 200) {
            log.warn("code: " + code);
        }
    }
    catch (final Throwable th) {
        log.warn(th.getMessage());
    }
    return res;
}

@iNoles Nope, same mistake. After "ok.newCall(req).execute();" you already have implicit body, which you have to close. And in case of "if (!response.isSuccessful())" - you don't close it -> causes warning.

You just need to close the ResponseBody from your Response, as stated a many times above.
Something like the following:

String get(String url) {
  Request req = new Request.Builder().url(url).get().build();
  try {
    Response resp = ok.newCall(req).execute();
    ResponseBody body = resp.body();
    if (resp.isSuccessful()) {
        return body.string(); // Closes automatically.
    } else {
        body.close();
        return null;
    }
  } catch (IOException e) {
    log.print(e.getMessage());
    return null;
  }
}

How does this works with timeouts? How can I close the response body if I don't have any response body ref to begin with?

private boolean isReachable(Host host, int connectTimeout) {
    boolean reachable = false;

    OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
            .readTimeout(connectTimeout, TimeUnit.MILLISECONDS)
            .build();

    try {
        Request request = new Request.Builder()
                .url(host.getCanonicalName())
                .build();

        client.newCall(request).execute().body().close();
        reachable = true;
    } catch (Exception exc) {
        reachable = false;
    }

    return reachable;
}
    Response response;
    try {
        Request request = new Request.Builder()
                .url(host.getCanonicalName())
                .build();

        response = client.newCall(request).execute();
        reachable = true;
    } catch (Exception exc) {
        reachable = false;
    } finally {
        if (response != null) response.body().close();
    }

@swankjesse wouldn't that be quite the same thing? if timeout is reached an exception would be thrown and still no response.body() would be available..

Yeah, you’re right. I’ll try to reproduce.

@JakeWharton I'm using Retrofit2 + okhttp3 in a java application fx, but I'm with the sample Which problem? Most call body (). String () Which closes it for you.
In my project I have a ServiceCreator class to create the retrofit coneções and okhttp, but the call I am not able to make a close in the body, following the examples:

`public class ServiceGenerator {

public static OkHttpClient.Builder httpClient;

public static Retrofit createRetrofit(String token) {

if (httpClient == null){
    httpClient = new OkHttpClient.Builder();
    if (token != null){
        httpClient.addInterceptor(new Interceptor() {
            @Override
            public okhttp3.Response intercept(Interceptor.Chain chain) throws IOException {
                Request original = chain.request();

                Request.Builder requestBuilder = original.newBuilder()
                        .header("Authorization", "Token token=" + token)
                        .method(original.method(), original.body());


                Request request = requestBuilder.build();

                return chain.proceed(request);
            }
        });
    }
    httpClient.connectTimeout(50, TimeUnit.SECONDS);
    httpClient.addInterceptor(addLoggin());



}

OkHttpClient client = httpClient.build();
Retrofit retrofit = new Retrofit.Builder().baseUrl(Constant.BASEURL)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create(new GsonBuilder()
                .excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC).create())).client(client).build();


return retrofit;

}

public static S createService(String token, Class serviceClass) {
return createRetrofit(token).create(serviceClass);
}

private static HttpLoggingInterceptor addLoggin(){

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();

logging.setLevel(HttpLoggingInterceptor.Level.NONE);
return logging;

}
}`

Usage into a ScheduleServe to polling:

`CatalogListener catalogListener = ServiceGenerator.createService(token, CatalogListener.class);

Call<List<Category>> call = catalogListener.syncMerchantId(merchantId);

call.enqueue(new Callback<List<Category>>() {

    @Override
    public void onResponse(Call<List<Category>> call, retrofit2.Response<List<Category>> response) {

// System.out.println(response.body());
cb.onResponse(response.body());
}

    @Override
    public void onFailure(Call<List<Category>> call, Throwable t) {
        System.out.println(t);
        cb.onFailure(t);
    }
});`

@JakeWharton Is it guaranteed, that Response.body() is always != null? Javadoc is unfortunately silent about it.

A variation on the last example the @swankjesse posted is to use java.util.Optional (Java 8) to outsource the null-assertion conditional, like so:

Response response = null;
try {
    // ...
} catch (IOException e) {
    // ...
} finally {
    Optional.ofNullable(response).ifPresent((res) -> res.body().close());
}

...though another difference is that response needs to be initialized to null (rather than simply declared), or else there's a compile error.

I do have to say, this whole thing makes for a pretty weird api

This really is kind of a strange design. Are there plans to change this behaviour eventually? The worst thing is that close() throws an IOException which causes another try ... catch in the finally block if you don't want to throw it...

This is what your calling code should look like.

    Request request = new Request.Builder()
        .url("https://publicobject.com/helloworld.txt")
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      Headers responseHeaders = response.headers();
      for (int i = 0; i < responseHeaders.size(); i++) {
        System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
      }

      System.out.println(response.body().string());
    }

I wouldn't call this code/API beautiful.

In Android (API 26), you don't open any "body" explicitly. You just use Url.openConnection(). Every time I get a response code 301 or 302 for a page, then after opening another page I get the error "Did you forget to close a response body". This doesn't happen for 404s. So there must be an error in the okhttp implementation in the Android API at least.

Example: Just run testpage() below in your MainAcitivity's onCreate.

package com.testhttp.whatever;

import android.util.Log;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class test {

    private static String getpage(String Url) {
        StringBuilder pageContent = new StringBuilder();
        int responseCode=0;
        try {
            URL httpUrl = new URL(Url);

            HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
            if (conn!=null) {
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);
                responseCode = conn.getResponseCode();
                if (responseCode != 200) throw new IllegalAccessException(" http connection failed");

                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = br.readLine()) != null) pageContent.append(line);
                conn.disconnect(); //doesn't help
            }
        } catch (IOException e) {
            e.printStackTrace(); //this catches timeouts
        }
        catch (IllegalAccessException e) {
            Log.d("test","responsecode="+responseCode);
            e.printStackTrace(); //this catches responsecode != 200
        }

        return pageContent.toString();
    }

    static void testpage() {
        new Thread() {
            public void run() {
                Log.d("test",getpage("http://topsy.one/"));
                Log.d("test",getpage("https://google.com/"));
            }
        }.start();
    }

}


@mb040574 you are not closing BufferedReader.

BufferedReader br = null;
try {
        URL httpUrl = new URL(Url);

        HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();
        if (conn!=null) {
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            responseCode = conn.getResponseCode();
            if (responseCode != 200) throw new IllegalAccessException(" http connection failed");

            br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = br.readLine()) != null) pageContent.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace(); //this catches timeouts
    }
    catch (IllegalAccessException e) {
        Log.d("test","responsecode="+responseCode);
        e.printStackTrace(); //this catches responsecode != 200
    } finally {
      if (br != null) {
          br.close();
    }
}
return pageContent.toString();

@iNoles The code never gets down to the BufferedReader in case of response code 301/302, and I have tried to close br. It doesn't help. Also conn.disconnect() doesn't help.

private static String getpage(String Url) {
        StringBuilder pageContent = new StringBuilder();
        int responseCode=0;

        BufferedReader br=null;
        HttpURLConnection conn=null;

        try {
            URL httpUrl = new URL(Url);

            conn = (HttpURLConnection) httpUrl.openConnection();
            if (conn!=null) {
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(5000);
                responseCode = conn.getResponseCode();
                if (responseCode != 200) throw new IllegalAccessException(" http connection failed");

                br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = br.readLine()) != null) pageContent.append(line);
                conn.disconnect(); //doesn't help
            }
        } catch (IOException e) {
            e.printStackTrace(); //this catches timeouts
        }
        catch (IllegalAccessException e) {
            Log.d("test","responsecode="+responseCode);
            e.printStackTrace(); //this catches responsecode != 200
        }

        try {
            if (br!=null) br.close(); //doesn't help
        } catch (Exception ignored) {}
        try {
            if (conn!=null) conn.disconnect(); //doesn't help
        } catch (Exception ignored) {}

        return pageContent.toString();
    }


@mb040574
HttpURLConnection is an abstract class, if you debug what is actual implementation it is usually:
com.android.okhttp.internal.huc.HttpURLConnectionImpl
and if you look at the implementation of disconnect() method you will find the answer:

// This doesn't close the stream because doing so would require all stream
// access to be synchronized. It's expected that the thread using the
// connection will close its streams directly. If it doesn't, the worst
// case is that the GzipSource's Inflater won't be released until it's
// finalized. (This logs a warning on Android.)

Well, the funny thing is that on the 64bit emulator this issue does not occur.

Calling string() closes the body, yes.

damn if I only new this 2 hours ago. i did a null check before using response.body().string() and each time i was trying to use it the response was closed.

So thank you for this. I think it would have taken me another couple of hours before i could figure it out

How to close body when you are using Okhttp with volley?.

class OkHttpStack extends HurlStack {

    private final OkUrlFactory okUrlFactory;

    OkHttpStack() {
        this(new OkUrlFactory(new OkHttpClient()));
    }

    private OkHttpStack(OkUrlFactory okUrlFactory) {
        if (okUrlFactory == null) {
            throw new NullPointerException("Client must not be null.");
        }
        this.okUrlFactory = okUrlFactory;
    }

    @Override
    protected HttpURLConnection createConnection(URL url) throws IOException {
        return okUrlFactory.open(url);
    }

}
synchronized RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(mContext,new OkHttpStack());
        }
        return mRequestQueue;
    }

Please also see this:
https://github.com/google/ExoPlayer/issues/3726

com.google.android.exoplayer2.upstream.DefaultHttpDataSource

will leak connections for a 404 response from the server

W/OkHttpClient: A connection to http://203.36.100.86/ was leaked. Did you forget to close a response body?
W/OkHttpClient: A connection to http://203.36.100.37/ was leaked. Did you forget to close a response body?
W/OkHttpClient: A connection to http://127.0.0.1:8080/ was leaked. Did you forget to close a response body?

The reason is that the okhttp3.internal.connection.RealConnection keeps track of which of the three streams (input, output and error) it believes its client has opened. If they are not closed before disconnect then it sees this as an error.

I might have the answer for the problem at begining of this thread

(I read the firsts posts were the guy talks about having 99 normal connection and 1 with problem and other people say that should close in case code != 200, but i didn't read the whole thread is it got super long)

I'm using okhttp with retrofit in my API, this API is stable and i've working with it for 2 years already...

I started a new app using my api and everything was Ok, but then i needed to test something very quickly in the app so I decided to use

try {
            URLConnection conn = new URL(somesite).openConnection();
            conn.connect();
            //((HttpURLConnection) conn).disconnect();
            return true;
        } catch (Exception e) {
            return false;
        }

after this I start getting

W/OkHttpClient: A connection to http://... was leaked. Did you forget to close a response body?

Well that is true, I didn't close the response body, but I was not using okhttp for that. I still dont know how okhttp got resource leak from my URLConnection but that was the reason.

So I decided to share to let other people with similar problem may check this posibility

@bolds07 Android uses OkHttp internally as of Android 4.4 which I think causes the warning.

@jemaystermind, on android even when I use disconnect i'm getting this warning... do you know what can i do in order to stop it?

@jemaystermind So does Retrofit 2.x automatically close response bodies for us or do we have to do it ourselves?

My approach if i want to just fetch the status code of the response

Request req = new Request.Builder().url(url).build();
try(Response res = ok.newCall(req).execute()) {
   System.out.println(resp.code());
}

This uses java 7's auto closable feature

If you look into the implementation of the close() method in Response class you can see that it in turn calls the close() method of response body. Below is the actual code for easy reference.

public void close() {
    if (this.body == null) {
        throw new IllegalStateException("response is not eligible for a body and must not be closed");
    } else {
        this.body.close();
    }
}

@jemaystermind, on android even when I use disconnect i'm getting this warning... do you know what can i do in order to stop it?

Same here, I'm not even using OkHttp, and in my code I close the connection:

private int pushToRemote() {
        JSONArray jsonArray = new JSONArray(pendingUploads.values());
        HttpURLConnection conn = null;
        int responseCode = UPLOAD_FAILED;
        try {
            URL address = new URL(url);
            conn = (HttpURLConnection) address.openConnection();
            conn.setReadTimeout(TIMEOUT);
            conn.setConnectTimeout(TIMEOUT);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestMethod(POST);
            conn.setDoInput(true);
            conn.setDoOutput(true);
            OutputStream output = conn.getOutputStream();
            OutputStreamWriter writer = new OutputStreamWriter(output, Charset.forName("UTF-8"));
            writer.write(jsonArray.toString());
            writer.flush();
            writer.close();
            output.close();
            responseCode = conn.getResponseCode();
        } catch (IOException e) {
            Log.e(UploadLogsWorker.class.getName(), "Error uploading to server " + e.getMessage());
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
        return responseCode;
    }

Yet, when I'm running a Instrumented test I see this line:
2018-12-12 11:44:27.898 25514-26209/******.test W/OkHttpClient: A connection to http://******:10301/ was leaked. Did you forget to close a response body?

I use try/finally but I still get warn message MANY TIMES.

`[OkHttp ConnectionPool] WARN okhttp3.OkHttpClient - A connection to some_site was leaked. Did you forget to close a response body? To see where this was allocated, set the OkHttpClient logger level to FINE: Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);

In my Kotlin's project:
`

import okhttp3.OkHttpClient
var оkHttpClient = OkHttpClient()
 val orderBookResponse = оkHttpClient.newCall(requestOrderBook).execute()
 val orderBookResponseBody = orderBookResponse.body()
        try {
            if (orderBookResponseBody != null) {
                val orderBookResponseBodyString = orderBookResponseBody.string()
                val bodyJsonElement = parser.parse(orderBookResponseBodyString)
            }
        } finally {
            if (orderBookResponseBody != null) {
                orderBookResponseBody.close()
            }
        }

Just saw this in my logs from Firebase Crashlytics init. Hopefully relevant / authoritative:

It looks like it was decided this was a platform issue, rather than anything at the app level. As a result, the logged warning was removed from the platform in https://android-review.googlesource.com/c/platform/external/okhttp/+/460418.

I am so glad can the comments from author. In my case I am useing Response rather than ResponseBody, so how can I close .
package com.heitouyang.promise.server.callback;

import android.content.Intent;

import androidx.annotation.NonNull;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.heitouyang.promise.activity.LoginActivity;
import com.heitouyang.promise.app.ZActivityManager;
import com.heitouyang.promise.app.ZApplication;
import com.heitouyang.promise.retrofit.APIClient;
import com.heitouyang.promise.server.resp.base.RespBody;
import com.heitouyang.promise.util.Logger;
import com.heitouyang.promise.util.ZPreference;
import com.heitouyang.promise.util.ZToast;

import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

/**

  • Created by zw.zhang on 2017/8/17.
    */

public abstract class ZCallBackWithFail implements Callback {
/**
* override this method to do some thing after fail.
*/
public boolean fail;

public ZCallBackWithFail() {
}

public abstract void callBack(T response);

@Override
public void onResponse(@NonNull Call<T> call, @NonNull Response<T> response) {
    if ((response.code() != 200) || response.body() == null || (response.body().errcode != 0)) {
        fail = true;
    }
    if (response.code() >= 500) {
        fail = true;
        ZToast.toast("服务器暂时无法为您提供服务,请稍后再试");
    } else if (response.code() == 401) {
        loginOut("你需要重新登录");
        return;
    }

    try {
        if (response.body() != null && response.body().errcode != 0) {
            long errCode = response.body().errcode;
            if (errCode == -10000 || errCode == -10001 || errCode == -10006 || errCode == -10007 || errCode == -1012 || errCode == -1014) {
                String m = "你的账号已在其他设备登录,是否重新登录";
                if (errCode == -10001 || errCode == -10000) {
                    m = "登录过期,需要重新登录";
                } else if (errCode == -1012) {
                    m = "用户不存在";
                }
                loginOut(m);
            } else {
                ZToast.alertDialog(response.body().errmsg);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        callBack(response.body());
    }
}

private void loginOut(String m) {
    if (ZPreference.isLogin()) {
        APIClient.getInstance().getApiInterface().loginOutNotRxjava().enqueue(new ZCallBackWithFail<RespBody>() {
            @Override
            public void callBack(RespBody response) {

                ZPreference.clear();
                Intent intent = new Intent("android.intent.action.MY_BROADCAST");
                intent.putExtra("msg", "hello receiver.");
                ZApplication.APP.get().sendBroadcast(intent);
                LocalBroadcastManager.getInstance(ZApplication.APP.get()).sendBroadcast(intent);
                ZToast.showLoginOutDialog(m, (dialog) -> ZActivityManager.getInstance().getCurrentActivity().startActivity(new Intent(ZApplication.APP.get(), LoginActivity.class)));
            }
        });
    }
}

@Override
public void onFailure(Call<T> call, Throwable t) {
    t.printStackTrace();
    Logger.e(t.getMessage());
    if (ZApplication.APP != null && ZApplication.APP.get() != null) {
        APIClient.initApiClient();
    }
    fail = true;

    if (t instanceof UnknownHostException || t instanceof SocketTimeoutException) {
        ZToast.toast("网络环境差,请检查网络设置");
    } else {
        ZToast.toast("服务器暂时无法为您提供服务,请稍后再试");
    }

    try {
        callBack(null);
    } catch (Exception e) {
        e.printStackTrace();
    }

}

}

I found "OkHttpClient: A connection to http://test-api.heitouyang.cn/ was leaked. Did you forget to close a response body?" should throw from glide. I do nothing about the glide OkHttpClient. How can I solve this with glide.

It is wired. According to try-with-resources

The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.

public final class Response implements Closeable {
...

So I think this would work

        try (Response response = postCall(WRITE_LOG, payload)) {
            return true;
        }

because response would be closed by try-with-resources.
However tomcat warns that the connection was leaked.

Was this page helpful?
0 / 5 - 0 ratings