OkHttp3 Never Timeout при медленном интернете

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

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

Проблема:

Я использую библиотеку Okhhtp3 в своем приложении для веб-служб. Он работает нормально, но когда интернет-соединение медленное или ненадежное, оно зависает и никогда не истекает и никогда не вызывает метод исключения или сбоя тайм-аута.

Вот код клиента:

OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .retryOnConnectionFailure(false)
            .build();

Как получить исключение тайм-аута или вызванный метод сбоя через 20 секунд?

Пожалуйста помогите. Спасибо

Вы пытались установить callTimeoutMillis на 20 секунд? Это плохо документировано, но, глядя на источник, он использует тайм-аут Okio для прерывания операции: см. github.com/square/okhttp/blob/… и github.com/square/okio/blob/master/okio/jvm/src/main/java/ok‌​io/….

Trevor Halvorson 12.03.2019 19:09

Документы найдены здесь: Square.github.io/okhttp/3.x/okhttp/okhttp3/… > Тайм-аут вызова охватывает весь вызов: разрешение DNS, подключение, запись тела запроса, обработка сервера и чтение тела ответа. Если вызов требует перенаправления или повторных попыток, все они должны завершиться в течение одного периода ожидания.

Trevor Halvorson 12.03.2019 19:18

@TrevorHalvorson общая продолжительность вызова, если я рассчитываю в соответствии с моим кодом общего доступа, составляет 1 минуту, но вызов продолжается до тех пор, пока я не убью приложение.

Tanveer Munir 13.03.2019 07:17

@TrevorHalvorson, как я могу установить callTimeoutMillis для клиента, метод не предусмотрен.

Tanveer Munir 13.03.2019 07:23

Метод вызова OkHttpClient.Builder — callTimeout. Вы можете использовать его так же, как и другие методы тайм-аута (connectTimeout и т. д.), которые вы используете в настоящее время. см.: Square.github.io/okhttp/3.x/okhttp/okhttp3/…

Trevor Halvorson 13.03.2019 17:46

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

Tanveer Munir 14.03.2019 08:09

@TanveerMunir, если вы используете okhttp3callTimeout, определенно доступен во время сборки.

shadowsheep 14.03.2019 18:19

@shadowsheep Я использую com.squareup.okhttp3:okhttp:3.11.0, поэтому он недоступен в этом, поэтому теперь я изменился, надеюсь, это сработало для меня.

Tanveer Munir 15.03.2019 07:10
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
18
8
3 565
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Как указал Тревор Халворсон, вы можете установить callTimeout во время сборки клиента следующим образом:

OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(20, TimeUnit.SECONDS)
            .callTimeout(20, TimeUnit.SECONDS)
            .writeTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .retryOnConnectionFailure(false)
            .build();

Я лично тестировал фиктивный проект, используя версию 3.14.0 из okhttp3:

implementation 'com.squareup.okhttp3:okhttp:3.14.0'

И установив таймаут 5 секунд и мой эмулятор связь на GPRS и Бедныхвозможность подключения я получаю

java.net.SocketExcpetion: Socket closed: timeout

Это мой полный фиктивная деятельность:

package com.example.shadowsheep.myapplication;

import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.concurrent.TimeUnit;

import androidx.appcompat.app.AppCompatActivity;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final TextView helloTextView = findViewById(R.id.helloTextView);

        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(5, TimeUnit.SECONDS)
                .callTimeout(5, TimeUnit.SECONDS)
                .writeTimeout(5, TimeUnit.SECONDS)
                .readTimeout(5, TimeUnit.SECONDS)
                .retryOnConnectionFailure(false)
                .build();

        Request request = new Request.Builder()
                .url("https://www.versionestabile.it/blog")
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                e.printStackTrace();
                Log.d("OKHTTP3", e.getMessage());
                // You get this failure
                runOnUiThread(() -> helloTextView.setText("TIMEOUT - FAILURE -> " + e.getMessage()));
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                try {
                    final String _body = response.body().string();
                    Log.d("OKHTTP3", _body);
                    runOnUiThread(() -> {
                        helloTextView.setText(_body);
                    });
                } catch (InterruptedIOException e) {
                    runOnUiThread(() -> {
                        // Or this exception depending when timeout is reached
                        helloTextView.setText("TIMEOUT EXCEPTION->"+ e.getCause() + ": " + e.getMessage());
                    });
                }
            }
        });
    }
}

Я дам вам также мой файл приложения build.gradle.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.example.shadowsheep.myapplication"
        minSdkVersion 24
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility 1.8
        targetCompatibility 1.8
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.1.0-alpha03'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test:runner:1.1.2-alpha02'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha02'

    implementation 'com.squareup.okhttp3:okhttp:3.14.0'
}

Я использую com.squareup.okhttp3:okhttp:3.11.0, поэтому он недоступен в этом, так что теперь я изменился, теперь надеюсь, что это сработало для меня.

Tanveer Munir 15.03.2019 07:11

@TanveerMunir Это должно работать ;-]. Меня устраивает. Дайте мне знать.

shadowsheep 15.03.2019 07:47

@TanveerMunir Вы пробовали мой код? Вы увидите, что получили InterruptedIOException. Если мой код работает, ваш тоже должен работать. Попробуйте, тогда, если вы хотите дать мне свой рабочий код, чтобы попробовать, я буду рад его протестировать.

shadowsheep 15.03.2019 09:36

Я использую один клиент для всего своего приложения. Я застреваю, когда соединение медленное и срок действия данных истек. Я не знаю, почему. Я использую calltimeout, но та же проблема

Tanveer Munir 15.03.2019 09:47

Давайте продолжить обсуждение в чате.

shadowsheep 15.03.2019 09:50

на самом деле, я не использую try/catch в ответе, поэтому оно застревает в моем приложении, и в ответ приходит исключение, и я предполагал, что это произойдет с ошибкой. Так что теперь он работает нормально. Я протестирую все приложение, после чего отмечу ответ и назначу вам награду.

Tanveer Munir 15.03.2019 12:01

Мой тестовый пример тоже не сработает, каждый раз требуется 30+ секунд:

  • Эмулятор Android Nexus 4 (версия Android 4.1.2)
  • Windows 7 без подключения к Интернету (убедитесь, что эмулятор не подключен к Интернету)

градиент:

implementation 'com.squareup.okhttp3:okhttp:3.12.2'

defaultConfig {
    minSdkVersion 16
    targetSdkVersion 26
}
compileSdkVersion 27
buildToolsVersion '28.0.3'

Джава:

public static class CheckIpAsyncTask extends util.android.os.AsyncTask<Void, Void, Void> {

@Override
    protected Void doInBackground(Void... voids) {
        try {
        Logger.i(TAG, "API::FBD::checkIpInfo, API_IPINFO = " + API_IPINFO);
        if (BuildConfig.DEBUG) {
            //ThreadUtil.sleep(10 * TimeUtil.SECOND);
        }

        Request req = new Request.Builder()
                .get()
                .url(API_IPINFO)
                .build();
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(2, TimeUnit.SECONDS)
                .callTimeout(2, TimeUnit.SECONDS)
                .readTimeout(2, TimeUnit.SECONDS)
                .writeTimeout(2, TimeUnit.SECONDS)
                .build();
        Response response = client.newCall(req).execute();

        mHttpCode = response.code();
        if (mHttpCode == HttpURLConnection.HTTP_OK) {
            boolean appConnected = ServerHelper.checkAppConnected();
            if (!appConnected) {
                JSONObject res = new JSONObject(response.body().string().trim());
                mCountry = res.getString("country").toLowerCase();
                mIp = res.getString("ip").toLowerCase();
                Logger.i(TAG, "API::FBD::checkIpInfo, res = " + res);

                PreferenceHelper.get(mContext).setIpInfoApiCountry(mCountry);
                PreferenceHelper.get(mContext).setIpInfoApiHost(mIp);
            }
        }
    } catch (java.io.InterruptedIOException interruptedIOException) {
        Logger.e(TAG, "API::FBD::checkIpInfo, InterruptedIOException = " + interruptedIOException);
    } catch (Throwable ignored) {
        Logger.e(TAG, "API::FBD::checkIpInfo, Throwable = " + ignored);
    }
    return null;
}

журналы:

04-04 06:25:06.940 4492-4645/? I/Toolbox: [PLACE] at com.xy.ui.FbdUtil$CheckIpAsyncTask.doInBackground(FbdUtil.java:98)
                                          [FbdUtil]API::FBD::checkIpInfo, API_IPINFO = http://api.z.com:30070/servers/ipinfo
04-04 06:25:34.960 4492-4645/? E/Toolbox: [PLACE] at com.xy.ui.FbdUtil$CheckIpAsyncTask.doInBackground(FbdUtil.java:129)
                                          [FbdUtil]API::FBD::checkIpInfo, InterruptedIOException=java.io.InterruptedIOException: timeout

журналы на эмуляторе Nexus 6 (версия Android 8.0):

04-04 06:52:44.696 2624-3950/? I/Toolbox: [PLACE] at com.xy.ui.FbdUtil$CheckIpAsyncTask.doInBackground(FbdUtil.java:98)
                                          [FbdUtil]API::FBD::checkIpInfo, API_IPINFO = http://api.z.com:30070/servers/ipinfo
04-04 06:53:59.886 2624-3175/? E/Toolbox: [PLACE] at com.xy.ui.ForbiddenUtil$CheckIpAsyncTask.doInBackground(FbdUtil.java:129)
                                          [FbdUtil]API::FBD::checkIpInfo, InterruptedIOException=java.io.InterruptedIOException: timeout

Наконец, решение Дмитрия Зеновича в «Вопросе 6» у меня работает:

.dns(hostname -> Single.fromCallable(() -> Arrays.asList(InetAddress.getAllByName(hostname)))
                            .timeout(2, TimeUnit.SECONDS)
                            .subscribeOn(Schedulers.io())
                            .observeOn(Schedulers.computation())
                            .onErrorReturnItem(new ArrayList<>())
                            .blockingGet())

Другие вопросы по теме