retrofit事實上就是對okhttp作了進一步一層封裝優化。php
咱們僅僅需要經過簡單的配置就能使用retrofit來進行網絡請求了。css
Retrofit可以直接返回Bean對象,好比假設咱們進行一個網絡接口的請求。返回來一串json字符串。那麼這個時候通常咱們都要拿到這個json字符串後進行解析獲得相應的Bean對象,Retrofit僅僅要依賴一下Gson的轉換庫而後進行簡單的配置就可以直接拿到Bean對象了,不需要咱們本身去解析。html
接觸過OKHttp的人會發現,Retrofit和OKHttp的代碼有些地方有很大的相似度。java
他的性能很的棒,國外大牛(被牆了)已經作過測例如如下圖:android
看了這個圖以後你有什麼想法?ios
Talk is cheap, show me the code!git
!github
在實際項目開發中get、post請求使用居多。那咱們以get請求來作個入門小案例。json
http://ip.taobao.com/service/getIpInfo.php?ip=8.8.8.8
以上鍊接是一個get請求方式。參數在地址後面使用「?」進行名值對的拼接。請求的結果是一個json字符串數據。例如如下api
{"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地址所在的國家。
現在預計不多人用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裏面的。
佈局很easy就不另貼代碼了。類也很少參看如下的包結構圖
可以直接使用工具轉化。如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;
}
}
通常來說都是處理遵循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簡單有用案例 * * 採用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()); } }); } }
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()); } } }
拼接注意,建議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使用,等下回分解!