Retrofit踩坑日記:response.body().string()只能調用一次


總覽和相關鏈接

這個作業屬於哪個課程 2021春/S班
這個作業要求在哪里 軟件工程實踐總結&個人技術博客
這個作業的目標 總結個人技術

技術概述

我在開發新聞app的過程中需要請求服務器數據,Retrofit框架在網絡請求方面封裝的很好,因此我選擇學習它,該技術的難點在於它的設計原理十分復雜,它利用了注解和okhttp框架給程序員帶來了極大的便利。

技術詳述

首先先創建一個接口:

public interface NewsService {
    @POST("index") //必須用post請求
    @FormUrlEncoded
    Call<BaseResponse> post(@Field("type") String type, @Field("key") String key);

    @GET("index")
    Call<ResponseBody> get(@Query("type") String type, @Query("key") String key);
}

核心方法:先配置Retrofi構造器的addConverterFactory方法,讓它可以自動實現json數據轉換成實體類,在baseurl函數的參數里填上要訪問的網絡地址,利用Retrofit框架對NewsService進行實現,然后調用NewsService的post方法,然后在子線程中進行網絡請求,主線程等待子線程處理完畢,將得到的數據返回。

 public List<News> getData(String type) throws InterruptedException {
        List<News>[] newsList = new List[]{new ArrayList<>()};
        Retrofit retrofit = new Retrofit.Builder().baseUrl("https://v.juhe.cn/toutiao/")
                .addConverterFactory(GsonConverterFactory.create()) //添加轉換器build();
                .build();
        NewsService newsService = retrofit.create(NewsService.class); //Retrofit將這個接口進行實現
        Call<BaseResponse> call = newsService.post(type, "4b3b9c355a55f676605532d37cf0d66c");
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Response<BaseResponse> response = call.execute();
                    BaseResponse baseResponse = response.body();
                    newsList[0] = baseResponse.getResult().getData();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
        thread.join();
        Log.d("lifecycle", String.valueOf(newsList[0].size())); //0?
        return newsList[0];
    }

流程圖:

技術使用中遇到的問題和解決過程。

問題:我打算將服務器返回的json數據進行解析,解析出來的對象一直是空,我還以為我導入的GSON庫有問題,浪費了很多時間。
貼上錯誤代碼

 public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
              try {
                   Log.d("RetrofitActivity", response.body().string());
                  //String result = response.body().string();
                  BaseResponse baseResponse = new Gson().fromJson(response.body().string(), BaseResponse.class);
                  System.out.println(baseResponse);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }

注意看我調用了兩次response.body().string(),原來response.body().string()只能調用一次,第二次為空。因為response.body().string()所包含的資源往往很大 ,當客戶端接收到數據之后,okhttp的緩沖區就會自動釋放資源!!

解決方案:

public void onResponse(retrofit2.Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
              try {
                   //Log.d("RetrofitActivity", response.body().string());
                  String result = response.body().string();
                  BaseResponse baseResponse = new Gson().fromJson(result, BaseResponse.class);
                  System.out.println(baseResponse);
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }

總結

當調用response.body().string()獲取數據時,response.body().string()只能調用一次,因此我們可以新建變量將數據存儲下來再進行后面的處理。犯這種錯誤的原因主要還是因為對網絡框架的原理不夠了解。

參考文獻

OkHttp踩坑記:為何 response.body().string() 只能調用一次? 作者:ruicbAndroid


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM