總覽和相關鏈接
這個作業屬於哪個課程 | 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