【问题标题】:Android Retrofit 2 file upload is not workingAndroid Retrofit 2 文件上传不起作用
【发布时间】:2017-03-28 01:53:18
【问题描述】:

我想开发一个可以上传任何类型文件的应用程序。我得到了源代码。但它仅适用于图像。并且只能上传小于 2 MB 大小的图像文件。我想上传所有类型的文件。请帮我。我的代码如下所示。

MainActivity.java

public class MainActivity extends AppCompatActivity {
Service service;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button btn = (Button) findViewById(R.id.btn_upload);

    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

    // Change base URL to your upload server URL.
    service = new Retrofit.Builder().baseUrl("http://192.168.1.4/work/filesharing/").client(client).build().create(Service.class);

    if (btn != null) {
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                String filePath1 = "/storage/emulated/0/gt.png";

                File file = new File(filePath1);

                RequestBody reqFile = RequestBody.create(MediaType.parse("*/*"), file);
                MultipartBody.Part body = MultipartBody.Part.createFormData("uploaded_file", file.getName(), reqFile);
                RequestBody name = RequestBody.create(MediaType.parse("text/plain"), "upload_test");



                retrofit2.Call<okhttp3.ResponseBody> req = service.postImage(body, name);
                req.enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { }

                    @Override
                    public void onFailure(Call<ResponseBody> call, Throwable t) {
                        t.printStackTrace();

                        Log.d("failure", "message = " + t.getMessage());
                        Log.d("failure", "cause = " + t.getCause());
                    }
                });

            }
        });
    }
}

}

上传 2MB 以上的 zip 文件时会出现错误。

11-14 17:09:14.369 13895-13960/app3.acs.com.file_upload2 D/OpenGLRenderer: Enabling debug mode 0
11-14 17:09:16.068 13895-13993/app3.acs.com.file_upload2 D/OkHttp: --> POST http://192.168.1.4/work/filesharing/6.php HTTP/1.1
11-14 17:09:16.068 13895-13993/app3.acs.com.file_upload2 D/OkHttp: Content-Type: multipart/form-data; boundary=b2c1d03e-f7a5-4e3f-89e1-d1c20358f7dc
11-14 17:09:16.070 13895-13993/app3.acs.com.file_upload2 D/OkHttp: Content-Length: 20862337
11-14 17:09:16.934 13895-13919/app3.acs.com.file_upload2 W/art: Suspending all threads took: 30.363ms
11-14 17:09:16.935 13895-13993/app3.acs.com.file_upload2 I/art: Alloc partial concurrent mark sweep GC freed 20318(40MB) AllocSpace objects, 0(0B) LOS objects, 35% free, 28MB/44MB, paused 644us total 49.776ms
11-14 17:09:18.272 13895-13993/app3.acs.com.file_upload2 I/art: Alloc sticky concurrent mark sweep GC freed 8(256B) AllocSpace objects, 0(0B) LOS objects, 10% free, 68MB/76MB, paused 1.012ms total 6.892ms
11-14 17:09:18.293 13895-13993/app3.acs.com.file_upload2 I/art: Alloc partial concurrent mark sweep GC freed 6(192B) AllocSpace objects, 0(0B) LOS objects, 18% free, 68MB/84MB, paused 1.310ms total 18.796ms
11-14 17:09:18.330 13895-13993/app3.acs.com.file_upload2 I/art: Alloc concurrent mark sweep GC freed 6(12KB) AllocSpace objects, 0(0B) LOS objects, 18% free, 68MB/84MB, paused 627us total 34.490ms
11-14 17:09:18.332 13895-13993/app3.acs.com.file_upload2 I/art: Forcing collection of SoftReferences for 36MB allocation
11-14 17:09:18.371 13895-13993/app3.acs.com.file_upload2 I/art: Alloc concurrent mark sweep GC freed 11(344B) AllocSpace objects, 0(0B) LOS objects, 18% free, 68MB/84MB, paused 569us total 38.975ms
11-14 17:09:18.373 13895-13993/app3.acs.com.file_upload2 E/art: Throwing OutOfMemoryError "Failed to allocate a 38772598 byte allocation with 16777120 free bytes and 27MB until OOM"
11-14 17:09:18.381 13895-13993/app3.acs.com.file_upload2 E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
                                                                       Process: app3.acs.com.file_upload2, PID: 13895
                                                                       java.lang.OutOfMemoryError: Failed to allocate a 38772598 byte allocation with 16777120 free bytes and 27MB until OOM
                                                                           at java.lang.String.<init>(String.java:332)
                                                                           at java.lang.String.<init>(String.java:371)
                                                                           at okio.Buffer.readString(Buffer.java:579)
                                                                           at okio.Buffer.readString(Buffer.java:562)
                                                                           at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:195)
                                                                           at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:187)
                                                                           at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:160)
                                                                           at okhttp3.RealCall.access$100(RealCall.java:30)
                                                                           at okhttp3.RealCall$AsyncCall.execute(RealCall.java:127)
                                                                           at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
                                                                           at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                                                                           at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                                                                           at java.lang.Thread.run(Thread.java:818)
11-14 17:09:20.069 13895-13993/app3.acs.com.file_upload2 I/Process: Sending signal. PID: 13895 SIG: 9

【问题讨论】:

    标签: android file-upload retrofit2 okhttp


    【解决方案1】:

    我在上传大图片或视频时遇到了同样的问题。主要问题是您在 HttpLoggingInterceptor 中使用正文级别,而 logger 正在 logcat 中打印您的文件,触发 java.lang.OutOfMemoryError 异常。

    如果您不想禁用正文级别的登录,您可以添加此代码以避免登录打印大文件内容。我创建了自己的 HttpLoggingInterceptor 并添加了一个 if 条件以在 content-length > 10Ks 的情况下跳过正文登录。

    HttpLoggingInterceptor 是一个 final 类,所以你不能覆盖它。您可以复制 HttpLoggingInterceptor 文件并替换此原始代码:

    if (!logBody || !hasRequestBody) {
                logger.log("--> END " + request.method());
            } else if (bodyEncoded(request.headers())) {
                logger.log("--> END " + request.method() + " (encoded body omitted)");
            } else {
                Buffer buffer = new Buffer();
                requestBody.writeTo(buffer);
                //[...]
    

    使用此代码:

    if (!logBody || !hasRequestBody) {
                logger.log("--> END " + request.method());
            } else if (bodyEncoded(request.headers())) {
                logger.log("--> END " + request.method() + " (encoded body omitted)");
            } else if (requestBody.contentLength()>1024 * 10) { //>10Kb
                logger.log("--> END " + request.method() + " (contentLength > 10Kb --> omitted)");
            } else {
                Buffer buffer = new Buffer();
                requestBody.writeTo(buffer);
                //[...]
    

    我希望这可以帮助任何人。对不起我的英语;)。

    【讨论】:

      【解决方案2】:

      请降低日志记录级别或将其全部删除

      看看 JakeWharton 在此链接上的回复https://github.com/square/retrofit/issues/540

      “通过调用 .setLogLevel(RestAdapter.LogLevel.FULL) 你强制 Retrofit 将整个请求体缓冲到内存中以便它可以记录。这就是在堆栈跟踪中调用 readBodyToBytesIfNecessary 所做的。

      只有在调试时才应该启用这样的日志记录。”

      【讨论】:

      • 删除所有日志拦截器
      • 删除那些行 HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();拦截器.setLevel(HttpLoggingInterceptor.Level.BODY);
      • 我删除了 /*HttpLoggingInterceptor 拦截器 = new HttpLoggingInterceptor();拦截器.setLevel(HttpLoggingInterceptor.Level.BODY); OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();*/ 并添加 /* OkHttpClient client = new OkHttpClient(); */ 然后显示错误是“Explicit concurrent mark sweep GC freed 93284(5MB) AllocSpace objects, 0(0B) LOS objects, 40% free, 9MB/16MB, paused 1.389ms total 266.514ms” 这个问题是怎么解决的?
      【解决方案3】:

      与这个问题有关https://github.com/square/retrofit/issues/540 .您可以禁用拦截器 Level.BODY。 它可以适用于所有类型的文件,您是否尝试过其他类型的文件?

      【讨论】:

      • 是的,我尝试过其他类型的文件,它只支持 2 mb 以下的图像。
      • 您是否尝试过像这样更改此拦截器日志记录:HttpLoggingInterceptor.Level.NONE
      • 是的。但它不起作用。没有上传文件。而且也没有在日志中显示任何内容。
      【解决方案4】:

      你也可以参考这里https://futurestud.io/tutorials/retrofit-2-how-to-upload-files-to-server这将有助于上传文件

      【讨论】:

        【解决方案5】:

        我得到了答案。这是xampp服务器中的问题。现在我可以发送大文件了。我从这个链接得到了答案 How to Increase Import Size Limit in phpMyAdmin using Xampp server?

        但是速度很慢。无论如何它都可以正常工作。

        【讨论】:

          【解决方案6】:

          我有同样的问题,但我发现库中没有问题。我的问题解决了。 它的服务器端问题。 您可以检查以下几点来解决它:-

          1. 检查可以将多长时间的文件上传到服务器。
          2. 从服务器的角度检查服务器连接超时。
          3. 确保您还必须更改 Apache 服务器上的文件大小。 (在我的例子中,apache 服务器的 php 文件大小是 5MB)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-09-04
            • 2017-05-14
            • 2016-08-31
            • 2017-10-06
            • 1970-01-01
            • 1970-01-01
            • 2017-07-02
            • 1970-01-01
            相关资源
            最近更新 更多