簡介
????????Retrofit是Square公司開發的一個類型安全的HTTP客戶端庫,用于Android和Java平臺,它使得與Web服務的交互變得更加簡單快捷。Retrofit將HTTP API轉換成Java接口,讓你可以用更簡潔的代碼形式調用RESTful API,Android網絡編程重點之一,基于互聯網,從服務器上獲取數據。
一、添加依賴(資源包)
需要添加的依賴:
com.squareup.retrofit2:retrofit:2.x.y
com.squareup.okhttp3:okhttp:4.9.1
com.squareup.retrofit2:converter-scalars:2.x.y
com.squareup.retrofit2:converter-gson:2.x.y
org.jsoup:jsoup:1.17.2
首先,在你的build.gradle.kts
(Module級別)文件中添加Retrofit的依賴:
在versions中添加名稱及版本
retrofit = "2.9.0"
gson="2.9.0"
在libraries中添加到相應的地址,包名,配置管理
retrofit = {group = "com.squareup.retrofit2", name ="retrofit",version.ref = "retrofit"}
gson={group="com.squareup.retrofit2",name="converter-gson",version.ref="gson"}
最后在"dependencies"(依賴關系)中添加上文中的名稱
implementation(libs.retrofit)implementation(libs.gson)
二、定義API接口
創建一個接口來描述Web服務的端點。Retrofit會根據這個接口生成實現類。
原理:
public interface ApiService {@GET("users/{user}/repos")Call<List<Repo>> listRepos(@Path("user") String user);
}
實例:
public interface WHttp {@GET("api/weather/city/{id}")Call<ReSon> getCall(@Path("id") String id);
}
創建 Retrofit 實例
????????創建一個接口來描述Web服務的端點。Retrofit會根據這個接口生成實現類。
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.github.com/").addConverterFactory(GsonConverterFactory.create()) // 如果你使用Gson解析JSON.client(new OkHttpClient()).build();
這里,@GET
注解指定了HTTP的GET方法,{user}
是一個動態部分,將由@Path
注解的參數填充。
三、創建服務接口的實例
創建實例:
使用Retrofit實例來創建API接口的實例,并用gson中的addConverterFactory()方法解析數據
四、發送請求:
創建Retrofit服務接口實例
WHttp wHttp = retrofit.create(WHttp.class);
這一行代碼通過Retrofit實例創建了一個名為WHttp
的服務接口實現。WHttp
接口應該事先定義好,包含了一些用于定義HTTP請求的方法,比如這里的getCall
方法。
構建請求
Call<ReSon> call = wHttp.getCall("101260101");
調用WHttp
接口中的getCall
方法,并傳入參數"101260101"
(這個參數根據實際接口需求可能代表某種ID或查詢條件)。這個操作返回一個類型為Call<ReSon>
的對象,表示一個即將發出的HTTP請求,目的是獲取一個ReSon
類型的響應數據。
異步執行請求enqueue
call.enqueue(new Callback<ReSon>() {//...
});
使用enqueue
方法異步發送請求。它不會阻塞當前線程,適合在主線程中調用,避免UI凍結。
onResponse
@Override
public void onResponse(Call<ReSon> call, Response<ReSon> response) {ReSon reSon = (ReSon) response.body();textView.setText(reSon.getDate());
}
????????當請求成功完成并且服務器返回一個成功的響應(HTTP狀態碼在200-299之間)時,onResponse
方法會被調用。通過response.body()
獲取到服務器返回的ReSon
對象,然后從中提取數據(這里假設ReSon
類有一個getDate
方法用于獲取日期信息),并將這個信息設置到一個名為textView
的TextView控件中顯示。
onFailure
@Override
public void onFailure(Call<ReSon> call, Throwable t) {textView.setText("錯誤" + t);
}
????????如果請求過程中出現錯誤,比如網絡問題、超時、服務器無響應等,onFailure
方法會被觸發。這里簡單地將錯誤信息以文本形式顯示在textView
中,實際應用中可能需要更細致的錯誤處理,比如根據錯誤類型給出不同的提示信息,或者進行重試邏輯等。
總的來說,這段代碼演示了如何使用Retrofit發送一個異步HTTP請求,處理成功響應和失敗情況的基本模式。
五、最總代碼:
WHttp wHttp = retrofit.create(WHttp.class);Call<ReSon> call = wHttp.getCall("101260101");call.enqueue(new Callback<ReSon>() {@Overridepublic void onResponse(Call<ReSon> call, Response<ReSon> response) {ReSon reSon = response.body();textView.setText(reSon.getDate());}@Overridepublic void onFailure(Call<ReSon> call, Throwable t) {textView.setText("錯誤"+t);}});
六、網絡安全錯誤
????????該錯誤信息表明您的應用程序嘗試與域名t.weather.itboy.net
建立網絡連接時,被網絡安全策略阻止了。這通常是因為現代操作系統和網絡框架為了提高安全性,會限制明文(未加密)的HTTP通信,鼓勵或強制使用HTTPS進行加密通信。
?????????解決這個問題的方法通常涉及到更新應用的網絡安全配置,允許特定域名的明文流量或者最好是確保所有通信都通過HTTPS進行。如果你的應用是運行在Android平臺上,可以通過以下步驟解決:
創建網絡安全配置文件:
????????????????在你的Android項目的res/xml
目錄下,創建一個名為network_security_config.xml
的文件(如果該目錄不存在,請先創建它),并添加如下配置以允許特定域名的明文流量(t.weather.itboy.net)(這不推薦用于生產環境,僅作示例):
1<?xml version="1.0" encoding="utf-8"?>
2<network-security-config>
3 <domain-config cleartextTrafficPermitted="true">
4 <domain includeSubdomains="true">t.weather.itboy.net</domain>
5 </domain-config>
6</network-security-config>
-
引用配置文件:
- 在你的應用的
AndroidManifest.xml
文件中,添加android:networkSecurityConfig
屬性指向剛才創建的配置文件:Xml1<application 2 ... 3 android:networkSecurityConfig="@xml/network_security_config"> 4 ... 5</application>
- 在你的應用的
-
重啟應用:
-
保存更改后,重新編譯并安裝你的應用到設備上。
-
然而,最安全的做法是確保t.weather.itboy.net
支持HTTPS,并且你的應用只通過HTTPS與之通信。如果該服務確實提供了HTTPS連接,請檢查你的應用程序代碼,確保所有URL都以https://
開頭而非http://
。
如果這是由于Android系統的安全策略(比如在Android 9及以上版本中對明文流量的限制),則上述解決方案是必要的。但在實施時,始終優先考慮應用和用戶數據的安全性。
?數據匹配錯誤
如下錯誤:
更正數據匹配為:
七、效果
八、異步與同步請求
????????Retrofit支持異步(如上所示使用enqueue
方法)和同步請求(使用execute
方法)。注意,同步請求不應該在主線程中執行,因為它會阻塞UI線程。在Retrofit中,異步請求通過enqueue
方法實現,而同步請求則通過execute
方法完成。下面分別給出這兩個操作的示例代碼,但請注意,同步請求應當避免在Android主線程中直接執行,以免阻塞UI,導致應用無響應(ANR)。
異步請求示例(已提供,再次展示以供參考)
1WHttp wHttp = retrofit.create(WHttp.class);
2Call<ReSon> call = wHttp.getCall("101260101");
3
4call.enqueue(new Callback<ReSon>() {
5 @Override
6 public void onResponse(Call<ReSon> call, Response<ReSon> response) {
7 if (response.isSuccessful()) {
8 ReSon reSon = response.body();
9 // 在這里處理響應數據,例如更新UI
10 runOnUiThread(new Runnable() {
11 @Override
12 public void run() {
13 textView.setText(reSon.getDate());
14 }
15 });
16 } else {
17 // 處理錯誤情況,例如HTTP錯誤碼
18 }
19 }
20
21 @Override
22 public void onFailure(Call<ReSon> call, Throwable t) {
23 // 處理網絡請求失敗的情況
24 runOnUiThread(new Runnable() {
25 @Override
26 public void run() {
27 textView.setText("錯誤: " + t.getMessage());
28 }
29 });
30 }
31});
同步請求示例
同步請求應當在后臺線程執行,例如使用Thread
或AsyncTask
(盡管AsyncTask
在Android 11及以上版本已被廢棄,推薦使用其他并發機制如java.util.concurrent
包下的工具類)。以下使用一個簡單的Thread
示例:
1new Thread(new Runnable() {
2 @Override
3 public void run() {
4 try {
5 WHttp wHttp = retrofit.create(WHttp.class);
6 Call<ReSon> call = wHttp.getCall("101260101");
7 Response<ReSon> response = call.execute();
8
9 if (response.isSuccessful()) {
10 final ReSon reSon = response.body();
11 // 由于不能直接在后臺線程更新UI,需要切換到主線程
12 runOnUiThread(new Runnable() {
13 @Override
14 public void run() {
15 textView.setText(reSon.getDate());
16 }
17 });
18 } else {
19 // 錯誤處理,同樣需要回到主線程更新UI
20 runOnUiThread(new Runnable() {
21 @Override
22 public void run() {
23 textView.setText("同步請求錯誤: " + response.code());
24 }
25 });
26 }
27 } catch (IOException e) {
28 e.printStackTrace();
29 // 異常處理,同樣需要回到主線程更新UI
30 runOnUiThread(new Runnable() {
31 @Override
32 public void run() {
33 textView.setText("同步請求失敗: " + e.getMessage());
34 }
35 });
36 }
37 }
38}).start();
在上述同步請求示例中,我們通過創建一個新的Thread
并在其中執行execute
方法來發送請求。由于execute
會阻塞直到請求完成,所以它不能直接在主線程中使用。請求完成后,我們使用runOnUiThread
回調到主線程更新UI,以確保遵循Android的單線程模型。