前言
retrofit基於okhttp封裝的網絡請求框架,網絡請求的工作本質上是 OkHttp 完成,而 retrofit 僅負責網絡請求接口的封裝.如果你不了解OKhttp建議你還是先了解它在來學習使用retrofit,傳送門:Android 開發 框架系列 OkHttp使用詳解
Retrofit優勢,就是簡潔易用,解耦,擴展性強,可搭配多種Json解析框架(例如Gson),另外還支持RxJava.但是,這篇博客不講解RxJava配合使用的部分,與RxJava的配合使用將在另外一篇博客中講解.
另外retrofit已經是封裝的非常好了,已經最大程度上的匹配各種使用情況,所以不建議多此一舉的再次封裝retrofit(最多封裝retrofit的單例). 再次封裝不會看起來很帥也不會讓你很牛逼. 只會讓你看起來更蠢.把已經很拓展很解耦的實現全部破壞.
Github地址
https://github.com/square/retrofit
依賴
如果你不需要使用RxJava模式,那么你只需要依賴下面2個:
implementation 'com.squareup.retrofit2:retrofit:2.6.2' implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
gson是用來解析的Json數據使用的(個人偏愛Gson),retrofit也支持其他解析工具比如fastJson
簡單的Demo(異步請求)
老規矩按思維順序講解demo
1.創建Retrofit請求基礎配置
Retrofit配置好后,可以全局使用這一個Retrofit用來請求網絡(所以你可以實現單例以全局使用),當然下面的代碼只是demo:
private Retrofit mRetrofit; private void initHttpBase(){ mRetrofit = new Retrofit.Builder() .baseUrl("http://doclever.cn:8090/mock/5c3c6da33dce46264b24452b/")//base的網絡地址 baseUrl不能為空,且強制要求必需以 / 斜杠結尾 .addConverterFactory(GsonConverterFactory.create())//使用Gson解析 .callbackExecutor(Executors.newSingleThreadExecutor())//使用單獨的線程處理 (這很重要,一般網絡請求如果不設置可能不會報錯,但是如果是下載文件就會報錯) .build(); }
注意! base的網絡地址 baseUrl不能為空,且強制要求必需以 / 斜杠結尾
2.創建數據返回后的Bean類
public class LoginBean { private int code; private String message; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
2.創建一個網絡請求接口
public interface HttpList { @FormUrlEncoded //注解表示from表單 還有@Multipart 表單可供使用 當然你也可以不添加 @POST("test/login_test") //網絡請求路徑 Call<LoginBean> login(@Field("number") String number, @Field("password") String password); //@Field("number") 為post值的的key }
注意,這是一個接口類. LoginBean則是數據返回后的Bean類(Retrofit會自動使用導入的Gson解析)
注意! @POST("test/login_test") 這路徑最前面不能加斜杠 / ,否則它會自動裁剪路徑,這樣會導致你的路徑錯誤
3.請求網絡
private void postHttp(){ HttpList httpList = mRetrofit.create(HttpList.class); Call<LoginBean> call = httpList.login("181234123", "123456"); call.enqueue(new Callback<LoginBean>() { @Override public void onResponse(Call<LoginBean> call, Response<LoginBean> response) { LoginBean bean = response.body(); Log.e(TAG, "onResponse: code="+bean.getCode()); Log.e(TAG, "onResponse: message="+bean.getMessage()); } @Override public void onFailure(Call<LoginBean> call, Throwable t) { Log.e(TAG, "onFailure: 網絡請求失敗="+t.getMessage()); } }); }
這樣,我們就完成了一個網絡請求.是不是特別簡單
同步請求
private void postHttp2() { HttpList httpList = mRetrofit.create(HttpList.class); final Call<LoginBean> call = httpList.login("181234123", "123456"); new Thread(new Runnable() { //Android主線程不能操作網絡請求,所以new一個線程來操作 @Override public void run() { try { Response<LoginBean> response = call.execute();//同步請求網絡 LoginBean bean = response.body(); Log.e(TAG, "onResponse: code=" + bean.getCode()); Log.e(TAG, "onResponse: message=" + bean.getMessage()); } catch (IOException e) { e.printStackTrace(); } } }).start(); }
取消網絡請求
public void cancelHttp(){ HttpList httpList = mRetrofit.create(HttpList.class); //這里貼這部分代碼是告訴call是哪里來的,關鍵點就是這個call,當然你也可以從回調里獲取 mCall = httpList.login("181234123", "123456"); mCall.cancel(); //取消請求 }
如何添加Header頭
以固定數據的形式添加頭信息
public interface HttpList { @Headers({"content1:one","content2:two"}) @POST("test/logout_test") Call<LoginBean> logout1(); }
以非固定數據的形式添加頭信息
public interface HttpList { @POST("test/logout_test") Call<LoginBean> logout2(@Header("content") String content); }
Body配置
Body一般有4個種類
- application/x-www-form-urlencoded 表單數據
- multipart/form-data 表單文件上傳
- application/json 序列化JSON數據
- text/xml XML數據
框架直接提供的2個Body
public interface HttpList { @FormUrlEncoded //application/x-www-form-urlencoded 表單body @POST("test/login_test") Call<LoginBean> login2(@Field("number") String number, @Field("password") String password); @Multipart //multipart/form-data 此body支持文件上傳與下載 @POST("test/login_test") Call<LoginBean> login3(@Field("number") String number, @Field("password") String password); }
自定義Body
其他2個就需要自定義創建了,下面舉例Json Body的創建:
/** * * @param string 直接導入需要發送給服務器的JSON的String值 * @return */ public static RequestBody getRequestBody(String string) { return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), string); }
在接口類參數需要設置為 @Body RequestBody requestBody
@POST("app/system/demo")
Observable<UpdateInfo> demo(@Body RequestBody requestBody);
添加配置的OkHttpClient(主要使用請求超時/攔截器等功能)
上面說了retrofit是基於Okhttp開發的網絡請求框架,所以它有一部分的功能依然需要使用Okhttp的方式來配置比如請求超時時間/設置攔截器等等,下面就展示一下如何添加
private void initHttpBase2() { OkHttpClient okHttpClient = new OkHttpClient.Builder() .retryOnConnectionFailure(false) //在連接失敗時重試 .callTimeout(30, TimeUnit.SECONDS) //呼叫超時,設置此參數為整體流程請求的超時時間 .connectTimeout(20,TimeUnit.SECONDS)//連接超時 .readTimeout(20,TimeUnit.SECONDS)//讀取超時 .writeTimeout(20,TimeUnit.SECONDS)//寫入超時 // .callTimeout()//呼叫超時,設置此參數為整體流程請求的超時時間 // .addInterceptor() //設置攔截器 // .authenticator() //設置認證器 // .proxy()//設置代理 .build(); mRetrofit = new Retrofit.Builder() .client(okHttpClient) .baseUrl("http://doclever.cn:8090/mock/5c3c6da33dce46264b24452b/")//base的網絡地址 .addConverterFactory(GsonConverterFactory.create())//使用Gson解析 .callbackExecutor(Executors.newSingleThreadExecutor()) .build(); }
部分路徑動態的BaseUrl
@POST("/article/query/{page}/json") @FormUrlEncoded Observable<DataResponse<Article>> getSearchArticles(@Path("page") int page, @Field("k") String k);
實現Url路徑傳參數
@Query 有值的查詢名稱
@GET("app/data")
Call<Result> getData(@Query("id") String id);
@GET("app/data")
Call<Result> getData(@Query("id") String... id);
@QueryName 只有值沒有key的傳參
@GET("app/data")
Call<Resul> getData(@QueryName String id);
@GET("app/data")
Call<Resul> getData(@QueryName String... id);
@QueryMap 用哈希集合傳值
@GET("app/data")
Call<Result> getData(@QueryMap Map<String,String> map);
end