Multipart OkHttp3/Retrofit 2 某些设备上传速度有问题

Vla*_*rov 2 android file-upload okhttp retrofit2

我有一个可以录制和上传视频文件的应用程序。我有一个记录onFailure Throwable每个文件上传的机制。

我注意到,在使用该应用程序的一千台设备中,有一些设备经常超时并且上传成功率很低。

有问题的设备是:Asus ZenPad C 7.0 Z170C

我已经购买了该设备并开始对其进行测试,但首先让您了解一下我使用的代码。

活动中:

    FileUploadService service = ServiceGenerator.createService(FileUploadService.class);

    File file = new File(getRealPathFromURI(mediaForUpload.mediaUri));
    ProgressRequestBody fileBody = new ProgressRequestBody(file, 
            new ProgressRequestBody.UploadCallbacks() {
                @Override
                public void onProgressUpdate(int uploadPercentage) {
                    // set current progress
                }
                @Override
                public void onError() {}
                @Override
                public void onFinish() {}
            });

    MultipartBody.Part body = MultipartBody.Part.createFormData(mediaForUpload.mediaNameWithExtension, mediaForUpload.mediaNameWithExtension, fileBody);

    Call<ResponseBody> call = service.upload(body);
    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
            if (response.isSuccessful()) {
            } else {
                 //Log
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            //Log
        }
    });
Run Code Online (Sandbox Code Playgroud)

在服务生成器中:

public static <S> S createService(Class<S> serviceClass) {
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(120, TimeUnit.SECONDS)
                .writeTimeout(120, TimeUnit.SECONDS)
                .readTimeout(120, TimeUnit.SECONDS)
                .build();

        Retrofit.Builder builder =
                new Retrofit.Builder()
                        .baseUrl("https://some.nice.api/")
                        .addConverterFactory(GsonConverterFactory.create());

        Retrofit retrofit = builder.client(client).build();
        return retrofit.create(serviceClass);
    }
Run Code Online (Sandbox Code Playgroud)

在文件上传服务中:

@Multipart
@POST("/somepath")
Call<ResponseBody> upload(@Part MultipartBody.Part file);
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我的超时时间是 120 秒,这很有趣,但这不足以成功上传 15MB 的视频文件而不超时。

我在华硕 Zenpad C 7.0三星 Tab 3 7"上进行了几次测试,只是为了向您展示差异。(测试在 2.4GHz 网络上,距离路由器 5 米;Tab 3 平均上传速度:1MB/s, Zenpad C7平均上传速度:~30KB/s(如果奇迹发生)

Android 监视器的屏幕截图:

  • 三星 Tab 3 7 英寸

三星 Tab 3

  • 华硕 Zenpad C 7.0

此后失败并超时 120: 120 秒后失败

经过这两次之后成功,但等待 1:35 分钟: 在此输入图像描述 在此输入图像描述

我测试了OkHttp3 Multipart upload,只是为了确定这不是Retrofit 2问题并且结果是相同的。

Vla*_*rov 5

经过两天的查找更多信息,我发现了问题所在。

首先,您必须知道默认套接字工厂的 getSendBufferSize() 为 524288。在我们的例子中,对于Asus Zenpad C 7.0来说这已经很多了。

我寻找解决方案的步骤是:

https://github.com/square/okhttp/issues/1078

并实施RestrictedSocketFactory https://gist.github.com/slightfoot/00a26683ea68856ceb50e26c7d8a47d0

之后我对我的代码做了一些修改:

    OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(120, TimeUnit.SECONDS)
            .writeTimeout(120, TimeUnit.SECONDS)
            .readTimeout(120, TimeUnit.SECONDS)
            .socketFactory(new RestrictedSocketFactory(bufferSize))
            .build();
Run Code Online (Sandbox Code Playgroud)

bufferSize的插座与我的插座sendBufferSize尺寸相同。我已经用 256*1024 和 128*1024 进行了测试,C 7.0 的最佳分辨率是 128*1024。不幸的是,所有其他设备的上传速度降低了约 30%,因此我制定了一种机制,仅将这些更改应用于几个设备。(根据我的测试,所有其他设备的最佳分辨率是 256*1024和)DEFAULT_BUFFER_SIZEProgressRequestBodybufferSizeDEFAULT_BUFFER_SIZE

这是使用Asus Zenpad C 7.0上传 17MB 视频文件的图片,您可以看到与第一篇文章的区别。

在此输入图像描述