【问题标题】:OkHttp3 Never Timeout on slow internetOkHttp3 在慢速互联网上从不超时
【发布时间】:2019-08-02 23:16:51
【问题描述】:

首先,我已经阅读了很多关于我的问题的问题,但它从来没有给我解决方案。以下是我阅读的关于我的问题的一些问题。

关于我的问题,我还阅读了此 article,但它也从未为我提供解决方案。

问题:

我在我的 Web 服务应用程序中使用 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/okio/…
  • 在此处找到文档:square.github.io/okhttp/3.x/okhttp/okhttp3/… > 调用超时跨越整个调用:解析 DNS、连接、写入请求正文、服务器处理和读取响应正文。如果调用需要重定向或重试,所有都必须在一个超时期限内完成。
  • @TrevorHalvorson 如果我根据我的共享代码计算的整体通话时间为 1 分钟,但除非我杀死应用程序,否则通话会持续运行。
  • @TrevorHalvorson 如何为客户设置callTimeoutMillis 没有提供方法。
  • OkHttpClient.Builder 上调用的方法是callTimeout。您可以像当前使用的其他超时方法(connectTimeout 等)一样使用它。见:square.github.io/okhttp/3.x/okhttp/okhttp3/…

标签: java android okhttp3 connection-timeout okhttp


【解决方案1】:

正如 Trevor Halvorson 所指出的,您可以在客户端构建期间设置 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.0okhttp3 版本在一个虚拟项目中进行了测试:

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

然后设置 5 秒的 timout 和我的模拟器 connectionGPRSPoor connectivity 我得到

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 这就是为什么它不可用所以现在我改变了希望它对我有用。
  • @TanveerMunir 它应该可以工作;-]。这个对我有用。告诉我。
  • @TanveerMunir 你试过我的代码了吗?你会看到你得到一个InterruptedIOException。如果我的代码有效,那么您的代码也应该有效。试试吧,如果你想给我一个你的工作代码来试试,我很乐意测试它。
  • 我在整个应用程序中使用单个客户端,当连接速度慢且数据过期时,我会卡住。我不知道为什么。我正在使用calltimeout 但同样的问题
【解决方案2】:

我的测试用例也不行,每次都需要 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'

java:

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

登录 Emulator 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

最后,Dmitry Zenovich 在“问题 6”中的解决方案对我有用:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    • 2011-04-01
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多