Android——Retrofit踩坑记(二)

版权声明:转载请标明出处: https://blog.csdn.net/Sunny_Captain/article/details/82690183

response.body().string()的猫腻…

在一段从服务器获取数据的代码中,刚开始我是如此写的:

call.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
                    try {
                        if (response.isSuccessful()) {
                            if (response.body().string().equals("")) {
                                //...
                            } else {
                                tv.setText(response.body().string());
                                //...
                            }
                        } else {
                            //...                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        //...
                    }
                }

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

第一眼看上去似乎没有毛病,如果响应成功,通过“response.body().string().equals(“”)”判断当前服务器返回的string内容是否为空,若为空则执行相应操作,若不为空则将“response.body().string()”的内容显示在一个TextView上。运行之后发现死活都没有数据显示出来,于是debug,发现两个if都会走,而response.body().string()在set到TextView那一步却变成空了…说明response.body().string()获取的字符串,在第二次调用时丢失了内容。
查阅相关源码后发现事实确实如此,并非bug。OkHttp请求回调中response.body().string()只能有效调用一次!
Okhttp源码中的ResponseBody.java文件的string()函数是这么写的:

/**
   * Returns the response as a string decoded with the charset of the Content-Type header. If that
   * header is either absent or lacks a charset, this will attempt to decode the response body in
   * accordance to <a href="https://en.wikipedia.org/wiki/Byte_order_mark">its BOM</a> or UTF-8.
   * Closes {@link ResponseBody} automatically.
   *
   * <p>This method loads entire response body into memory. If the response body is very large this
   * may trigger an {@link OutOfMemoryError}. Prefer to stream the response body if this is a
   * possibility for your response.
   */
  public final String string() throws IOException {
    BufferedSource source = source();
    try {
      Charset charset = Util.bomAwareCharset(source, charset());
      return source.readString(charset);
    } finally {
      Util.closeQuietly(source);
    }
  }

可以看到执行完string()方法后,IO流通过这一个语句被关闭了:Util.closeQuietly(source);
所以,OkHttp请求回调中response.body().string()只能有效调用一次!切记!文章开头的代码改成下面的写法则一切正常:

call.enqueue(new Callback<ResponseBody>() {
                @Override
                public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
                    try {
                        if (response.isSuccessful()) {
                            String result = response.body().string();
                            if (result.equals("")) {
                                //...
                            } else {
                                tv.setText(result);
                                //...
                            }
                        } else {
                            //...
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        //...
                    }
                }

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

猜你喜欢

转载自blog.csdn.net/Sunny_Captain/article/details/82690183