1. 程式人生 > >Retrofit 網路請求框架

Retrofit 網路請求框架

1、什麼是Retrofit框架?

它是Square公司開發的現在非常流行的網路框架

2.為什麼使用Retrofit框架

        效能好,處理快,使用簡單,Retrofit 是安卓上最流行的HTTP Client庫之一 預設使用OKHttp處理網路請求,我覺得可以看成是OKHttp的增強。預設使用Gson解析.

 怎麼配置Retrofit2.0?

//配置retrofit2.0
compile 'com.squareup.retrofit2:retrofit:+'
compile 'com.squareup.retrofit2:converter-gson:+'
//配置支援Rxjava2
compile 'com.squareup.retrofit2:adapter-rxjava2:+'
compile 'io.reactivex.rxjava2:rxjava:+'
compile 'io.reactivex.rxjava2:rxandroid:+'

1.構造Retrofit:

***baseUrl:****

1. 預設的伺服器地址,Retrofit在進行請求一個介面時會根據你填寫的

baseurl+方法名 去請求。

****addConverterFactory:****

新增返回資料的解析方式,Retrofit支援多種格式的解析,xml,json,

jackson,Moshi,Protobuf,wire等,新增對這些資料格式的支援同樣需要在

Gradle中進行依賴。這些依賴Square公司同樣提供了支援。

****CallAdapter:****

Retrofit會將網路請求的介面以回撥的方式返回,我們通常會得到一個叫做

Call<型別>的結果,如果我們需要返回其他的結果,例如RxJava形式的結果,需

要對RxJava做支援。如果不需要特殊型別的返回結果,我們是不需要配置的。

****Client:****

通過該方法我們可以新增自己定製的OkHttp

三、建立介面 宣告API

四、 Retrofit各個註解的含義及作用

GET註解     1. 用於傳送一個get請求     2. GET註解一般必須新增相對路徑或絕對路徑或者全路徑,如果不想在GET註解後新增請求路徑,則可以在方法的第一個引數中用@Url註解新增請求路徑。  Url註解:     1. 作用於方法引數     2. 用於新增請求的介面地址     3.示例:

@GET
Call<ResponseBody> list(@Url String url);
Path註解:     1. 作用於方法的引數     2. 在URL路徑段中替換指定的引數值。使用String.valueOf()和URL編碼     3. 將值轉換為字串。     4. 使值不可為用該註解定義的引數的空     5. 引數值預設使用URL編碼     6. 示例:
//預設使用URL編碼
@GET("/user/{name}")
Call<ResponseBody> encoded(@Path("name") String name);
//不使用URL編碼
@GET("/user/{name}")
Call<ResponseBody> notEncoded(@Path(value="name", encoded=true) String name);
 Query註解:      1. 作用於方法的引數      2. 用於新增查詢引數,即請求引數      3. 引數值通過String.valueOf()轉換為String並進行URL編碼      4. 使用該註解定義的引數,引數值可以為空,為空時,忽略該值,當傳入一個Listarray時,為每個非空item拼接請求鍵值對,所有的鍵是統一的,如:name=張三&name=李&name=王五.      5. 示例:
@GET("/list")
Call<ResponseBody> list(@Query("page") int page);
@GET("/list")
Call<ResponseBody> list(@Query("category") String category);
//傳入一個數組
@GET("/list")
Call<ResponseBody> list(@Query("category") String... categories);
//不進行URL編碼
@GET("/search")
Call<ResponseBody> list(@Query(value="foo", encoded=true) String foo);
 QueryMap註解:      1. 作用於方法的引數      2. 以map的形式新增查詢引數,即請求引數      3. 引數的鍵和值都通過String.valueOf()轉換為String格式      4. map的鍵和值預設進行URL編碼      5. map中每一項的鍵和值都不能為空,否則拋IllegalArgumentException異常      6. 示例:
//使用預設URL編碼
@GET("/search")
Call<ResponseBody> list(@QueryMap Map<String, String> filters);
//不使用預設URL編碼
@GET("/search")
Call<ResponseBody> list(@QueryMap(encoded=true) Map<String, String> filters);

POST註解:     1. 用於傳送一個POST請求     2. POST註解一般必須新增相對路徑或絕對路徑或者全路徑,如果不想在POST註解後新增請求路徑,則可以在方法的第一個引數中用@Url註解新增請求路徑 FormUrlEncoded註解:     1. 用於修飾Field註解和FieldMap註解     2. 使用該註解,表示請求正文將使用表單網址編碼。欄位應該宣告為引數,並用@Field註釋或FieldMap註釋。使用FormUrlEncodied註解的請求將具”applicaton / x-www-form-urlencoded” MIME型別 Field註解      1. 作用於方法的引數      2. 用於傳送一個表單請求

@FormUrlEncoded
@POST("/")
Call<ResponseBody> example(@Field("name") String name,@Field("occupation") String
        occupation);
//固定或可變陣列
@FormUrlEncoded
@POST("/list")
Call<ResponseBody> example(@Field("name") String... names);
 FieldMap註解:     1. 作用於方法的引數     2. 用於傳送一個表單請求     3. map中每一項的鍵和值都不能為空,否則丟擲IllegalArgumentException異常
@FormUrlEncoded
@POST("/things")
Call<ResponseBody> things(@FieldMap Map<String, String> fields);
 Header註解:     1. 作用於方法的引數,用於新增請求頭     2. 使用該註解定義的請求頭可以為空,當為空時,會自動忽略,當傳入一個List或array時,為拼接每個非空的item的值到請求頭中.具有相同名稱的請求頭不會相互覆蓋,而是會照樣新增到請求頭中     3. 示例:
@GET("/")
Call<ResponseBody> foo(@Header("Accept-Language") String lang);
 HeaderMap註解:      1. 作用於方法的引數,用於新增請求頭      2. 以map的方式新增多個請求頭,map中的key為請求頭的名稱,value為請求頭的值,且value使用String.valueOf()統一轉換為String型別,map中每一項的鍵和值都不能為空,否則丟擲IllegalArgumentException異常      3. 示例:
@GET("/search")
    void list(@HeaderMap Map<String, String> headers);
    //map
    Map<String,String> headers = new HashMap()<>;
headers.put("Accept","text/plain");
headers.put("Accept-Charset", "utf-8");
 Headers註解:     1. 作用於方法,用於新增一個或多個請求頭     2. 具有相同名稱的請求頭不會相互覆蓋,而是會照樣新增到請求頭中     3. 示例:
//新增一個請求頭
    @Headers("Cache-Control: max-age=640000")
    @GET("/")
...
//新增多個請求頭
    @Headers({"X-Foo: Bar",
            "X-Ping: Pong"
    })
    @GET("/")
...

2.1 HTTP註解: (瞭解)     1. 作用於方法,用於傳送一個自定義的HTTP請求     2. 示例:

//自定義HTTP請求的標準樣式
interface Service {
    @HTTP(method = "CUSTOM", path = "custom/endpoint/")
    Call<ResponseBody> customEndpoint();
}
//傳送一個DELETE請求
interface Service {
    @HTTP(method = "DELETE", path = "remove/", hasBody = true)
    Call<ResponseBody> deleteObject(@Body RequestBody object);
}
Multipart註解:     1. 作用於方法     2. 使用該註解,表示請求體是多部分的。 每一部分作為一個引數,且用Part註解宣告  Part註解:          1. 作用於方法的引數,用於定義Multipart請求的每個part          2. 使用該註解定義的引數,引數值可以為空,為空時,則忽略          3. 使用該註解定義的引數型別有以下3種方式可選:     1, 如果型別是okhttp3.MultipartBody.Part,內容將被直接使用。 省略   part中的名稱,即 @Part MultipartBody.Part part     2, 如果型別是RequestBody,那麼該值將直接與其內容型別一起使用。 在註釋中提供part名稱(例如@Part(“foo”)RequestBody foo)。     3, 其他物件型別將通過使用轉換器轉換為適當的格式。 在註釋中提供part名稱(例如,@Part(“foo”)Image photo)      4. 示例:
@Multipart
@POST("/")
Call<ResponseBody> example(
        @Part("description") String description,
        @Part(value = "image", encoding = "8-bit") RequestBody image);
 PartMap註解:      1. 作用於方法的引數,以map的方式定義Multipart請求的每個partmap中每一項的鍵和值都不能為空,否則丟擲IllegalArgumentException異常 使用該註解定義的引數型別有以下2種方式可選:      1, 如果型別是RequestBody,那麼該值將直接與其內容型別一起使用。      2, 其他物件型別將通過使用轉換器轉換為適當的格式。 示例:
@Multipart
@POST("/upload")
Call<ResponseBody> upload(
        @Part("efile") RequestBody file,
        @PartMap Map<String, RquestBody> params);

3.2 Streaming註解:      1. 作用於方法      2. 處理返回Response的方法的響應體,即沒有將body()轉換為byte[]。 

注意事項:

    1,以上部分註解真正的實現在ParameterHandler類中,,每個註解的真正實現都是ParameterHandler類中的一個final型別的內部類,每個內部類都對各個註解的使用要求做了限制,比如引數是否可空,鍵和值是否可空.

    2,FormUrlEncoded註解和Multipart註解不能同時使用

    3,Path註解與Url註解不能同時使用

    4,對於FiledMap,HeaderMap,PartMap,QueryMap這四種作用於方法的註解,其引數型別必須為Map的例項,且key的型別必須為String型別

    5,使用Body註解的引數不能使用form 或multi-part編碼,即如果為方法使用了FormUrlEncoded或Multipart註解,則方法的引數中不能使用Body註解

    6,Retrofit提供了MultiPart註解,說明我們可以上傳檔案,又提供了Streaming註解,說明我們可以下載檔案,我們知道Retrofit可以幹這些事,但是我們還是沒有辦法直接寫上傳下載程式碼,這些東西都需要我們自己去封裝,這也是為什麼目前有很多基於Retrofit構建的二次封裝庫的原因

Retrofit 網路請求之@Body標籤遇到的坑

程式碼:

/**
 * 封裝Retrofit網路請求框架
 * 懶漢式單例模式
 */
public class RetrofitManager {

    public static final String BASE_URL = "http://www.zhaoapi.cn/";
    private final Retrofit retrofit;

    // 靜態內部類的單例
    private static final class SINGLE_INSTANCE {
        private static final RetrofitManager _INSTANCE = new RetrofitManager();
    }

    public static RetrofitManager getInstance() {
        return SINGLE_INSTANCE._INSTANCE;
    }

    /**
     * 在構造方法中構造Retrofit物件
     * 設定公共url,解析方式gson,配置OkHttpClient
     */
    private RetrofitManager() {
        // 構造Retrofit物件
        retrofit = new Retrofit.Builder()
                // 設定公共的url部分
                .baseUrl(BASE_URL)
                // 配置解析方式為Gson
                .addConverterFactory(GsonConverterFactory.create())
                // 配置OKHttpClient
                .client(buildOkHttpClient())
                .build();
    }

    @NonNull
    private OkHttpClient buildOkHttpClient() {
        // 構造OkHttpClient物件
        return new OkHttpClient.Builder()
                .readTimeout(5, TimeUnit.SECONDS)
                .writeTimeout(5, TimeUnit.SECONDS)
                .connectTimeout(5, TimeUnit.SECONDS)
                .build();
    }

    /**
     * 因為retrofit在create的時候需要傳入class
     * 並且返回這個類
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T create(Class<T> clazz) {
        return retrofit.create(clazz);
    }
}
/**
 * 點選請求網路登入
 * @param view
 */
public void request(View view) {
    // 利用Retrofit.create方法構造一個Api介面的例項
    ILoginApi iLoginApi = RetrofitManager.getInstance().create(ILoginApi.class);

    // 構造一個Call請求,拿到Api介面的例項呼叫對應的方法去構造一個Call請求
    final Call<LoginBean> call = iLoginApi.login("login", "18210926066", "123456");
    /**
     * 非同步請求
     */
    call.enqueue(new Callback<LoginBean>() {
        @Override
        public void onResponse(Call<LoginBean> call, Response<LoginBean> response) {
            // 通過response.body拿到最後解析後的bean物件
            LoginBean loginBean = response.body();
            if (loginBean != null && "0".equals(loginBean.getCode())) {
                Toast.makeText(MainActivity.this, "請求成功", Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void onFailure(Call<LoginBean> call, Throwable t) {
            Toast.makeText(MainActivity.this, "請求失敗", Toast.LENGTH_SHORT).show();
        }
    });
}