OkHttp3 SocketTimeoutException (в приложении для Android) Как установить время ожидания чтения для асинхронного запроса?

Я продолжаю получать исключение java.net.SocketTimeoutException при попытке асинхронного получения OkHttp3. Это говорит о том, что я не установил достаточно большое значение времени ожидания чтения (я думаю, что значение по умолчанию составляет 10 секунд).

Более крупный вопрос: «Как предотвратить это исключение?» но, если у кого-то нет лучшей начальной стратегии, мой непосредственный вопрос: «Как установить значение тайм-аута чтения для запроса?»

В своем коде я использовал информацию со страницы рецептов Okttp здесь

Обратите внимание, что первые две строки моего try-catch закомментированы. Это потому, что я не могу использовать тип компоновщика (с возможностью установки значения времени ожидания, OkHttpClient.Builder), который мне нужен для добавления информации заголовка (Request.Builder).

Мой код выглядит так:

    m_client = new OkHttpClient();


    try
    {
        //OkHttpClient.Builder bldr = m_client.newBuilder();
        //bldr.readTimeout(0, TimeUnit.SECONDS);

        Request.Builder reqBuilder = new Request.Builder();

        reqBuilder.addHeader("authorization", getToken());

        Request request = reqBuilder.url("http://plusdev.kooklah.com/api/v2_1/items/get").build();

        m_client.newCall(request).enqueue(new Callback()
        {
            @Override
            public void onFailure(Call call, IOException e)
            {
                Log.i("Logit", "Inside onFailure() -- IOException: " + e.getMessage() + " ----- stack trace: " + UtilGen.exceptionToString(e));

                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                       // do stuff on UI thread
                    }
                });
            }

            @Override
            public void onResponse(Call call, final Response responseIn)
            {
                try
                {
                    m_sServerResponse = responseIn.body().string();
                }
                catch (Exception ex)
                {
                    Log.i("LogIt", "          ---Inside onResponse() -- Exception occurred. ex: " + ex.toString());
                }

                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Log.i("LogIt", "          ---Inside onResponse() -- inside run().");
                        if (!m_sServerResponse.isEmpty())
                        {
                            Log.i("LogIt", "          ---Inside onResponse() -- inside run() -- Success");
                            processDownloadedAssessments(m_sServerResponse);
                        }
                    }
                });
            }
        });
    }
    catch (Exception ex)
    {
        Log.i("LogIt", "ex: " + ex.getMessage());
    }

Я нашел сообщение о проблеме, которая, по-видимому, имеет непосредственное отношение, здесь, на сайте okhttp github. Есть даже рекомендация установить тайм-аут чтения, который, как упоминалось выше, был закомментирован, потому что я не могу понять, как использовать такой построитель для асинхронного запроса, как описано на странице рецептов.

Трассировка стека для моего исключения приведена ниже, но имейте в виду, что большую часть времени я не получаю исключение. Трассировки стека:

01-19 14:04:52.192: I/LogIt(25650): Inside onFailure() -- IOException: null ----- stack trace: java.net.SocketTimeoutException
01-19 14:04:52.192: I/LogIt(25650):     at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
01-19 14:04:52.192: I/LogIt(25650):     at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
01-19 14:04:52.192: I/LogIt(25650):     at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
01-19 14:04:52.192: I/LogIt(25650):     at okio.Okio$2.read(Okio.java:138)
01-19 14:04:52.192: I/LogIt(25650):     at okio.AsyncTimeout$2.read(AsyncTimeout.java:236)
01-19 14:04:52.192: I/LogIt(25650):     at okio.RealBufferedSource.indexOf(RealBufferedSource.java:325)
01-19 14:04:52.192: I/LogIt(25650):     at okio.RealBufferedSource.indexOf(RealBufferedSource.java:314)
01-19 14:04:52.192: I/LogIt(25650):     at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:210)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http1.Http1Codec.readResponse(Http1Codec.java:191)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:132)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:54)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.RealCall$AsyncCall.execute(RealCall.java:129)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
01-19 14:04:52.192: I/LogIt(25650):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
01-19 14:04:52.192: I/LogIt(25650):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
01-19 14:04:52.192: I/LogIt(25650):     at java.lang.Thread.run(Thread.java:818)

person Alyoshak    schedule 19.01.2017    source источник
comment
Построитель OkHttpClient и построитель Request — это два разных класса. Вы устанавливаете тайм-аут в OkHttpClient билдере, и он применяется ко ВСЕМ запросам. Вы устанавливаете заголовки для построителя Request для отдельных запросов.   -  person LordRaydenMK    schedule 19.01.2017
comment
Совершенно верно, но как ввести первое в запрос после установки его значения тайм-аута?   -  person Alyoshak    schedule 19.01.2017
comment
вы выполняете Request, используя OkHttpClient, созданный с помощью компоновщика с указанным тайм-аутом.   -  person LordRaydenMK    schedule 19.01.2017
comment
@LordRaydenMK - Как упоминалось в вопросе, для асинхронного вызова требуется класс Request.Builder, а не OkHttpClient.Builder.   -  person Alyoshak    schedule 19.01.2017
comment
У меня такая же проблема в котлине. Может кто поможет решить?   -  person tinto mathew    schedule 09.12.2019


Ответы (1)


Вместо

m_client = new OkHttpClient();

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

m_client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build();

Когда вы создаете такой клиент, каждый Request, выполняемый с этим клиентом (используя m_client.newCall(...)), будет использовать тайм-ауты, указанные в построителе.

person LordRaydenMK    schedule 19.01.2017
comment
Я чувствую запах того, что ты готовишь. Придется ненадолго отключиться, но постараюсь как можно скорее. Может быть завтра. Спасибо. - person Alyoshak; 19.01.2017
comment
Это была моя проблема, я не использовал вызов build() в построителе OkHttpClient после установки его тайм-аутов. - person Alyoshak; 20.01.2017
comment
Каково их соответствующее исключение при тайм-ауте? - person Beatrice Lin; 24.08.2017