天天看點

Android實戰——Retrofit2的使用和封裝

Retrofit2是什麼

使用項目的原話:Android和Java中類型安全的HTTP用戶端

項目位址:https://github.com/square/retrofit

Retrofit2的導入

這裡Retrofit還需要導入它的Gson依賴庫,因為傳回的資料需要Gson來處理

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'           

Retrofit2的基本使用

1、Get請求

2、Post請求

3、單、多檔案上傳

Retrofit2工具類的示範

示範提供的接口(該接口不支援post方式)

http://japi.juhe.cn/joke/content/list.from?key=488c65f3230c0280757b50686d1f1cd5&&sort=asc&&time=1418816972           

get請求(支援普通請求)

/*
 * Get請求 
 * 參數已經封裝在工具類的Url中
 */
Call<Info> call = RetrofitUtils.getInstance().get();
call.enqueue(new Callback<Info>() {
    @Override
    public void onResponse(Call<Info> call, Response<Info> response) {

    }

    @Override
    public void onFailure(Call<Info> call, Throwable t) {

    }
});           

get請求(支援鍵值對參數)

//根據接口需求建立鍵值對
Map<String,String> map = new HashMap<>();
map.put("key","488c65f3230c0280757b50686d1f1cd5");
map.put("sort","asc");
map.put("time","1418816972");

/*
 * Get請求 
 * @param map 為get參數
 */
Call<Info> call = RetrofitUtils.getInstance().get(map);
call.enqueue(new Callback<Info>() {
    @Override
    public void onResponse(Call<Info> call, Response<Info> response) {

    }

    @Override
    public void onFailure(Call<Info> call, Throwable t) {

    }
});           

Post請求(支援鍵值對參數)

//根據接口需求建立鍵值對
Map<String,String> map = new HashMap<>();
map.put("key","488c65f3230c0280757b50686d1f1cd5");
map.put("sort","asc");
map.put("time","1418816972");

/*
 * Post請求 
 * @param map 為Post參數
 */
Call<Info> call = RetrofitUtils.getInstance().post(map);
call.enqueue(new Callback<Info>() {
    @Override
    public void onResponse(Call<Info> call, Response<Info> response) {

    }

    @Override
    public void onFailure(Call<Info> call, Throwable t) {

    }
});           

Post請求(支援擷取傳回的字元串)

//根據接口需求建立鍵值對
Map<String,String> map = new HashMap<>();
map.put("key","488c65f3230c0280757b50686d1f1cd5");
map.put("sort","asc");
map.put("time","1418816972");

/*
 * Post請求 
 * @param map 為Post參數
 */
Call<ResponseBody> call = RetrofitUtils.getInstance().post(map);
call.enqueue(new Callback<ResponseBody>() {
    @Override
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        //這裡采用Retrofit2自帶的ResponseBody可以傳回對應的字元串資料,get請求同理
        String body = response.body().string().toString();
    }

    @Override
    public void onFailure(Call<ResponseBody> call, Throwable t) {

    }
});           

Post請求(上傳檔案和參數)

//檔案的封裝
List<MultipartBody.Part> parts = null;
parts = RetrofitUtils.filesToMultipartBodyParts("imgs[]", photo_list);
//參數的封裝
Map<String, RequestBody> params = new HashMap<>();
params.put("token", RetrofitUtils.convertToRequestBody("abcdefg"));
params.put("username", RetrofitUtils.convertToRequestBody("hensen"));
params.put("password", RetrofitUtils.convertToRequestBody("123456"));

//上傳檔案和參數
Call<Object> call = RetrofitUtils.getInstance().register(params, parts);
call.enqueue(new Callback<Object>() {
    @Override
    public void onResponse(Call<Object> call, Response<Object> response) {

    }

    @Override
    public void onFailure(Call<Object> call, Throwable t) {

    }
});           

Retrofit2工具類的封裝

Retrofit的請求是以REST請求方式發送請求的,是以工具的封裝需要做兩件事

  • 對REST請求的API進行封裝
  • Retrofit自身的封裝

由于我們接口傳回的JSON資料如下

{
    "error_code": 0,
    "reason": "Success",
    "result": {
        "data":[
            {
                "content":"學校論壇上有人問:“為啥明明用了除蟑螂的藥,蟑螂卻越來越多了。”某個學生回帖:“如果你家人不見了,你不出來找嗎?你會不着急麼?”",
                "hashId":"8196907ee902f3508b9be6ea59d2191c",
                "unixtime":1478598830,
                "updatetime":"2016-11-08 17:53:50"
            }
        ]
    }
}           

是以這裡需要對我們需要解析的資料進行Bean對象的封裝

public class Info {

    @Override
    public String toString() {
        return "Info{" +
                "error_code=" + error_code +
                ", reason='" + reason + '\'' +
                ", result=" + result +
                '}';
    }

    private int error_code;
    private String reason;
    private ResultBean result;

    public static class ResultBean {
        @Override
        public String toString() {
            return "ResultBean{" +
                    "data=" + data +
                    '}';
        }

        private List<DataBean> data;

        public static class DataBean {
            private String content;
            private String hashId;
            private int unixtime;
            private String updatetime;

            @Override
            public String toString() {
                return "DataBean{" +
                        "content='" + content + '\'' +
                        ", hashId='" + hashId + '\'' +
                        ", unixtime=" + unixtime +
                        ", updatetime='" + updatetime + '\'' +
                        '}';
            }
        }
    }
}           

對REST請求的API進行封裝

Retrofit使用注解的方式來聲明GET請求、POST請求、請求參數、請求頭等進行的網絡通路,下面是各個注解的表示的意思

  • Get請求相關
    • @Get:發送Get請求
    • @Query:Get請求參數
    • @QueryMap:Get請求Map參數
  • Post請求相關
    • @Post:發送Post請求
    • @FormUrlEncoded:采用表單的方式,一般與@Post共用
    • @Field:Post請求參數
    • @FieldMap:Post請求Map參數
  • Header請求相關
    • @Headers:發送Header資訊
    • @Header:Header資訊參數
    • @HeaderMap:Header資訊的Map參數
  • Path請求相關
    • @Path:通路路徑,最終通路[email protected]裡面的内容
了解完意思之後,編寫REST的API,其實就是請求接口,具體看下面的代碼
public interface IRetrofitServer {

    String getUrl = "list.from";
    String postUrl = "list.from";

    /**
     * 傳遞參數的Get請求
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @GET(getUrl)
    Call<Info> get(@Query("key") String key, @Query("sort") String sort, @Query("time") String time);

    /**
     * 封裝好Url的Get的請求
     * @return
     */
    @GET(getUrl + "?key=488c65f3230c0280757b50686d1f1cd5&&sort=asc&&time=1418816972")
    Call<Info> get();

    /**
     * 傳遞Map鍵值對的Get請求
     * @param params
     * @return
     */
    @GET(getUrl)
    Call<Info> get(@QueryMap Map<String, String> params);

    /**
     * 傳遞參數的Post請求
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> post(@Field("key") String key, @Field("sort") String sort, @Field("time") String time);

    /**
     * 傳遞Map鍵值對的Post請求
     * @param map
     * @return
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> post(@FieldMap Map<String, String> map);

    /**
     * 傳遞Map鍵值對的Post請求
     * @param map
     * @return 對應的字元串資料
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<ResponseBody> post(@FieldMap Map<String, String> map);

    /**
     * 傳遞Map鍵值對和Header的Post請求
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @Headers({"os:Android", "version:2.0"})
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> postWithHeader(@Field("key") String key, @Field("sort") String sort, @Field("time") String time);

    /**
     * 傳遞Map鍵值對和Header的Post請求
     * @param os
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> postWithHeader(@Header("os") String os, @Field("key") String key, @Field("sort") String sort, @Field("time") String time);

    /**
     * 傳遞Map鍵值對和Header的Post請求
     * @param map
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @FormUrlEncoded
    @POST(postUrl)
    Call<Info> postWithHeader(@HeaderMap Map<String, String> map, @Field("key") String key, @Field("sort") String sort, @Field("time") String time);

    /**
     * 傳遞通路路徑和鍵值對的Post請求
     * @param path
     * @param key
     * @param sort
     * @param time
     * @return
     */
    @FormUrlEncoded
    @POST("{path}")
    Call<Info> post(@Path("path") String path, @Field("key") String key, @Field("sort") String sort, @Field("time") String time);
}           

Retrofit自身的封裝

Retrofit和okHttp一樣,采用構造者模式建立,采用單例模式防止使用多個對象

private static final String baseUrl = "http://japi.juhe.cn/joke/content/";
private static Retrofit retrofit = null;
private static IRetrofitServer iServer;

public static IRetrofitServer getInstance() {
    if (retrofit == null) {
        synchronized (RetrofitUtils.class) {
            if (retrofit == null) {
                retrofit = new Retrofit.Builder()
                        .baseUrl(baseUrl)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
                iServer = retrofit.create(IRetrofitServer.class);
            }
        }
    }
    return iServer;
}           

上面代碼做了三件事

  • 綁定請求URL
  • 采用GSON來處理傳回的JSON資料
  • 建立并傳回REST請求API接口iServer
下面就可以直接使用工具類拿到這個iServer,調用提供的接口方法
Call<Info> call = RetrofitUtils.getInstance().get();
call.enqueue(...);           

單、雙檔案的上傳

API接口的建立,比如說注冊功能,需要上傳兩張身份證照片,這是我自己伺服器的接口

public interface IRetrofitServer {

    @Multipart
    @POST("app/register")
    Call<Object> register(@PartMap Map<String, RequestBody> map, @Part List<MultipartBody.Part> parts);
}           
  • @PartMap:表示參數的上傳
  • @Part:表示檔案清單

建立兩個方法輔助PartMap和Part的建立

//這裡的key則是背景伺服器的字段名,即使H5中input的name的名字
//如果是單檔案,filePaths的大小就為1
public static List<MultipartBody.Part> filesToMultipartBodyParts(String key, List<String> filePaths) {
    List<MultipartBody.Part> parts = new ArrayList<>(filePaths.size());
    for (String filePath : filePaths) {
        File file = new File(filePath);
        //這裡的image/*表示上傳的是相片的所有格式,你可以替換成你需要的格式
        RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
        MultipartBody.Part part = MultipartBody.Part.createFormData(key, file.getName(), requestBody);
        parts.add(part);
    }
    return parts;
}

public static RequestBody convertToRequestBody(String param) {
    //這裡的text/plain表示參數都是文本
    RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), param);
    return requestBody;
}           
到這裡,你就可以回過頭去看下文章開頭的示範部分,那裡就是RetrofitUtils的使用

工具類下載下傳:RetrofitUtils

由于檔案上傳是我在做項目的時候用上的,工具類缺少檔案上傳的内容,大家可以自行去拷貝代碼