1.簡單介紹
retrofit事實上就是對okhttp做了進一步一層封裝優化。
我們僅僅須要通過簡單的配置就能使用retrofit來進行網絡請求了。
Retrofit能夠直接返回Bean對象,比如假設我們進行一個網絡接口的請求。返回來一串json字符串。那么這個時候一般我們都要拿到這個json字符串后進行解析得到相應的Bean對象,Retrofit僅僅要依賴一下Gson的轉換庫然后進行簡單的配置就能夠直接拿到Bean對象了,不須要我們自己去解析。
接觸過OKHttp的人會發現,Retrofit和OKHttp的代碼有些地方有很大的類似度。
他的性能很的棒,國外大牛(被牆了)已經做過測例如以下圖:
看了這個圖之后你有什么想法?
Talk is cheap, show me the code!
!
2.高速使用
在實際項目開發中get、post請求使用居多。那我們以get請求來做個入門小案例。
http://ip.taobao.com/service/getIpInfo.php?ip=8.8.8.8
以上連接是一個get請求方式。參數在地址后面使用“?”進行名值對的拼接。請求的結果是一個json字符串數據。例如以下
{"code":0,"data":{"country":"\u7f8e\u56fd","country_id":"US","area":"","area_id":"","region":"","region_id":"","city":"","city_id":"","county":"","county_id":"","isp":"","isp_id":"","ip":"8.8.8.8"}}
來個簡單的Demo界面例如以下:
功能很easy,一個輸入框輸入IP地址,然后獲取IP地址所在的國家。
1)環境的配置
如今預計很少人用eclipse做項目開發了。eclipse的方式就不另贅述了(GitHub上也是有jar依賴下載的)。我們這里的開發工具是用的Android Studio,在 GitHub項目地址:https://github.com/square/retrofit能夠找到Gradle的依賴代碼:
加入兩個依賴:retrofit依賴。和gson轉換器。
compile 'com.squareup.retrofit2:retrofit:2.1.0'//眼下最新的版本號
compile 'com.squareup.retrofit2:converter-gson:2.1.0'//加入好這個依賴后我們就能夠進行數據轉換器的配置了。retrofit內部就會幫我們去轉換json字符串為Java對象
在AS里面的效果例如以下:
converter-gson依賴的版本號號與retrofit依賴版本號號保持一致。我們在GitHub上能夠看到。他們在同一個project里面的。
2)代碼
布局很easy就不另貼代碼了。類也不多參看以下的包結構圖
Retrofit操作步驟
① 先把接口返回來的數據bean對象寫好。
能夠直接使用工具轉化。如GsonFormat工具
public class IpInfo {
public int code;
public DataBean data;
public static class DataBean {
public String country;
public String country_id;
public String area;
public String area_id;
public String region;
public String region_id;
public String city;
public String city_id;
public String county;
public String county_id;
public String isp;
public String isp_id;
public String ip;
}
}
② 定義API接口
一般來講都是處理遵循RESTful接口規范的http接口,我們須要把接口轉化為Java Interface。
/** * 這個接口就是普通的借口類,可是看到里面的方法來,會有一些注解定義相關的功能 * 如@GET定義請求方式為get請求方式,假設有參數能夠使用@Query、@QueryMap定義 */
public interface IpService {
/** * @return 固定返回值為Call。當中泛型指定是進行請求后返回終於得數據類型。
*/ @GET("getIpInfo.php") //@GET 定義網絡請求方式 Call<IpInfo> getIpInfo(@Query("ip") String ip); //@Query("ip") 指的是傳入的參數名為ip。值為調用方法傳入的值形參ip }
③ 初始化Retrofit,創建接口實例,進行異步請求
代碼凝視灰常仔細了
/** *Retrofit簡單有用案例 * * 採用http://ip.taobao.com/service/getIpInfo.php?ip=202.178.10.2 地址進行查詢 */
public class MainActivity extends AppCompatActivity {
public static final String baseUrl = "http://ip.taobao.com/service/";
private TextView tvResult;
private EditText etIp;
IpService ipService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvResult = (TextView) findViewById(R.id.tv_result);
etIp = (EditText) findViewById(R.id.et_ip);
initRetrofit();
}
/** * 初始化Retrofit實例。並創建接口類。 * 注意:IpService不須要我們去實現。直接Retrofit=類有create方法生成。 */
private void initRetrofit() {
//創建Retrofit的實例,把Gson轉換器設置下
Retrofit retrofit = new Retrofit
.Builder()
.baseUrl(baseUrl)//設置API的基礎地址
.addConverterFactory(GsonConverterFactory.create())//設置后才才支持json字符串轉化為Bean
.build();
//使用Retrofit的create方法傳入創建接口實例
ipService = retrofit.create(IpService.class);
}
/** * 布局中查詢button配置的點擊事件 * @param view */
public void check(View view) {
String ip = etIp.getText().toString();
if (TextUtils.isEmpty(ip)) {
Toast.makeText(this, "ip 不能為空", Toast.LENGTH_SHORT).show();
return;
}
//調用接口聲明的方法
Call<IpInfo> ipInfoCall = ipService.getIpInfo(ip);
//call能夠直接調用異步方法。進行結果獲取。須要傳入接口回調Callback, ipInfoCall.enqueue(new Callback<IpInfo>() { @Override public void onResponse(Call<IpInfo> call, Response<IpInfo> response) { //推斷網絡請求是否成功。網絡請求返回code為[200..300)那么與后台連接成功。
否則連接失敗 if (response.isSuccessful()) { //直接拿到JavaBean IpInfo ipInfo = response.body(); //這里直接能夠進行UI操作。OKHttp是不行的哦 tvResult.setText(ipInfo.getData().getCountry()); } else { //請求失敗。
假設代碼執行到這里來說明是有跟后台握手的,是后台處理有問題,如404(沒有資源),500(后台報錯了) tvResult.setText("查詢失敗!! -->code="+response.code()); } } @Override public void onFailure(Call<IpInfo> call, Throwable t) { //請求失敗。如,沒有聲明網絡權限、沒有網絡、或者是Retrofit 異常內部處理異常(如Gson解析失敗)也是會到這里 t.printStackTrace(); tvResult.setText("查詢失敗:"+t.getCause()); } }); } }
3.經常使用注解
GET:get 請求方式
POST:post請求方式
Query:定義get請求參數
QueryMap:定義get請求參數
Field:定義post請求參數
FieldMap:定義post請求參數
Header:定義頭參數
HeaderMap:定義頭參數
Headers:定義頭參數
Path:動態路徑
來看看代碼是怎么實現的:
public interface SampleApi {
//----------------------GET 請求方式 start --------------------------------
/** * 注解:GET。QUERY,QUERYMAP 的使用 */
/** * get 請求固定參數形式 * * @return */
@GET("demo?username=zhanghsan&password=123455") Call<SampleResponse> getFun(); /** * 使用@Query注解進行參數傳遞 * * @param username * @param password * @return */ @GET("demo") Call<SampleResponse> getFun(@Query("username") String username, @Query("password") String password); /** * 使用@QueryMap注解 Map集合進行參數傳遞 * * @param params * @return */ @GET("demo") Call<SampleResponse> getFun(@QueryMap Map<String, Object> params); //----------------------GET 請求方式 end -------------------------------- //----------------------POST 請求方式 start -------------------------------- /** * POST,Field,FieldMap,FormUrlEncoded(POST 方式請求有參數的時候一定不要忘記了這個注解) */ /** * post使用@Query注解進行參數傳遞 * * @param username * @param password * @return */ @FormUrlEncoded @POST("demo") Call<SampleResponse> postFun(@Field("username") String username, @Field("password") String password); /** * POST使用@FiledMap Map集合進行參數傳遞 * * @param params * @return */ @FormUrlEncoded @POST("demo") Call<SampleResponse> postFun(@FieldMap Map<String, Object> params); //----------------------POST 請求方式 end -------------------------------- //----------------------head參數加入start -------------------------------- /** * Headers。Header,HeaderMap * */ /** * 有些接口須要傳送一些操作client系統的信息,比方系統類型。系統版本號等例如以下 * * @param username * @param password * @return */ @Headers( {"os:Android" , "osversion:5.0" }) @FormUrlEncoded @POST("demo") Call<SampleResponse> postFunWithHead(@Field("username") String username, @Field("password") String password); /** * 有些接口須要傳送一些操作client系統的信息,比方系統類型。系統版本號等例如以下 * * @param username * @param password * @return */ @FormUrlEncoded @POST("demo") Call<SampleResponse> postFunWithHead(@Header("os") String os, @Header("osversion") String osversion, @Field("username") String username, @Field("password") String password); /** * 有些接口須要傳送一些操作client系統的信息,比方系統類型,系統版本號等例如以下 * * @param headParams head 參數。鍵值對的形式存儲到map集合中去 * @param username * @param password * @return */ @FormUrlEncoded @POST("demo") Call<SampleResponse> postFunWithHead(@HeaderMap Map<String, String> headParams, @Field("username") String username, @Field("password") String password); //----------------------head參數加入end -------------------------------- //----------------------path 注解 -------------------------------- /** * Path注解使用時在請求方式注解后面的URL設置一個占位符,使用大括號包裹。
在方法形參類型前使用@Path("占位符")。 */ @FormUrlEncoded @POST("{path}") Call<SampleResponse> postFunWithHead(@Path("path") String path, @HeaderMap Map<String, String> headParams, @Field("username") String username, @Field("password") String password); }
Activity代碼
public class SampleActivity extends AppCompatActivity {
EditText etName;
EditText etPassword;
TextView tvResult;
SampleApi sampleApi;
SampleCallBack callback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
etName = (EditText) findViewById(R.id.et_name);
etPassword = (EditText) findViewById(R.id.et_password);
tvResult = (TextView) findViewById(R.id.tv_result);
//使用鏈式調用建立
sampleApi = new Retrofit
.Builder()
.baseUrl("http://10.0.2.2:8080/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(SampleApi.class);
callback = new SampleCallBack();
}
/** * button點擊事件 * * @param view */
public void submit(View view) {
tvResult.setText("正在請求....");
String name = etName.getText().toString();
String password = etPassword.getText().toString();
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(password)) {
Toast.makeText(this, "參數不能為空", Toast.LENGTH_SHORT).show();
return;
}
Call<SampleResponse> call;
switch (view.getId()) {
case R.id.btn_get:
call = sampleApi.getFun(name, password);
call.enqueue(callback);
break;
case R.id.btn_post:
call = sampleApi.postFun(name, password);
call.enqueue(callback);
break;
case R.id.btn_head:
// call = sampleApi.postFunWithHead(name, password);//第一種,直接靜態定義方式。看接口方法
// call = sampleApi.postFunWithHead("ios","10.10.10",name, password);//另外一種,能夠動態配置值得方式
Map<String, String> map = new HashMap<>();
map.put("os", "android");
map.put("osversion", "9.9.9999999");
// call = sampleApi.postFunWithHead(map, name, password);//第三種,能夠動態配置參數和值得形式
call = sampleApi.postFunWithHead("demo",map, name, password);//第四種,結合Path定義路徑
call.enqueue(callback);
break;
}
}
/** * @param result * 顯示結果 */
public void showResult(String result) {
tvResult.setText(result);
}
/** * 回調實現類 */
public class SampleCallBack implements Callback<SampleResponse> {
@Override
public void onResponse(Call<SampleResponse> call, Response<SampleResponse> response) {
//推斷網絡請求是否成功。網絡請求返回code為[200..300)那么與后台連接成功。否則連接失敗
if (response.isSuccessful()) {
//直接拿到JavaBean
SampleResponse sampleResponse = response.body();
//這里直接能夠進行UI操作。OKHttp是不行的哦
showResult(sampleResponse.toString());
} else {
//請求失敗。
假設代碼執行到這里來說明是有跟后台握手的,是后台處理有問題,如404(沒有資源),500(后台報錯了) showResult("查詢失敗。! -->code=" + response.code()); } } @Override public void onFailure(Call<SampleResponse> call, Throwable t) { //請求失敗。如。沒有聲明網絡權限、沒有網絡、或者是Retrofit 異常內部處理異常(如Gson解析失敗)也是會到這里 t.printStackTrace(); showResult("查詢失敗:" + t.getCause()); } } }
執行效果
4.URL操作注意事項
拼接注意,建議baseUrl用“/”結尾。接口中請求方式后面的url不用”/”開頭
樣例:baseUrl=http://10.0.2.2:8080/market/ url=home
錯誤案例
案例一:
baseUrl=http://10.0.2.2:8080/market url=home
—>http://10.0.2.2:8080/home
分析:默認用最后一個斜線去拼接
案例二:
baseUrl=http://10.0.2.2:8080/market url=/home
—>http://10.0.2.2:8080/home
分析:url中開始的斜線代表主機地址http://10.0.2.2:8080
Retrofit還能夠實現上傳下載以及 結合RxJava使用,等下回分解!