爲了跟上Android開發的技術潮流,最近在研究Retrofit。自己也嘗試在此基礎上封裝適合自己的網絡請求框架。工作的項目中所有請求都約定爲POST並且請求參數和響應結果都是JSON格式的。於是開始搜索“Retrofit提交JSON“,得到的結果和Retrofit的官方簡介上推薦的一樣的。那就是把請求封裝成bean,然後使用@Body來發送這個請求。代碼如下
public interface TaskService {
@POST("/tasks")
Call<Task> createTask(@Body Task task);
}
public class Task {
private long id;
private String text;
public Task(long id, String text) {
this.id = id;
this.text = text;
}
}
Task task = new Task(1, "my task title");
Call<Task> call = taskService.createTask(task);
call.enqueue(new Callback<Task>() {});
上述代碼的掣肘顯而易見,那就是需要爲每個請求都封裝一個bean。使用這種方式的博友們還專門提供了自動生成這樣的bean的工具類,可謂良苦用心。Java Web開發中也許習慣以bean作爲查詢條件,每張數據庫表對應一個bean,很容易獲得。即使bean中很多字段根本用不到,但是簡單粗暴將整個bean傳過去作爲參數,使用起來非常方便。而以移動端的開發習慣,我們並不會爲每個request封裝一個特定的bean。而只會爲每個response封裝一個bean或者叫model,用於反序列化響應結果。
下面看看Retrofit提交JSON的正確姿勢。
//定義接口
public interface ApiService {
/**
* request和response都是json形式,不使用系統默認的GsonConverter,拿到response後自己用Gson解析成bean
*/
@POST
Call<ResponseBody> postWithJson(@Url String url, @HeaderMap Map<String, String> headers, @Body RequestBody paramBody);
}
這裏的@HeaderMap是添加動態請求頭用的,比如cookie。不需要的可以去掉headers這個參數。
//封裝
@Override
public Call<ResponseBody> generateCall() {
RequestBody paramBody = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), mParamStr);//將參數包裝成RequestBody
return HttpRequest.sApiService.postWithJson(mUrl, mHeaderMap, paramBody);
}
mCall = mBuilder.generateCall();
mCall.enqueue(callback);
如果對你有幫助,這是生成代理對象的代碼
public class ServiceGenerator {
private static OkHttpClient.Builder okHttpclientBuilder;
private static Retrofit.Builder retrofitBuilder;
public static <S> S createService(Class<S> serviceClass) {
okHttpclientBuilder = new OkHttpClient.Builder();
//目前封裝的幾個接口都是沒有用到GsonConverter,是傳入ResponseBody,拿到響應結果後自己解析
retrofitBuilder = new Retrofit.Builder() .baseUrl(Config.baseUrl)
/*.addConverterFactory(GsonConverterFactory.create())*/;
Retrofit retrofit = retrofitBuilder.client(okHttpclientBuilder.build()).build();
return retrofit.create(serviceClass);
}
}
public static ApiService sApiService = ServiceGenerator.createService(ApiService.class);
以及實際使用的代碼
HttpRequest.builder(
new PostJsonBuilder()
.url(ApiUrl.LOGIN)
.defaultHeaders()
.param("mobile", "13*********")
.param("password", Md5.md5Toword("123456"))
.modelClazz(LoginModel.class)
.callback(new AbsCallback<LoginModel>() {
@Override
public void onBizSuccessOnUi(LoginModel model) {
UserInfo info = model.getData();
ToastUtils.showShort("登錄成功");
mBtnLogin.setText("登錄成功");
}
@Override
public void onBizFailureOnUi(LoginModel model) {
ToastUtils.showShort("登錄失敗");
}
})).startCall();
所有源碼可以在這裏查看Retrofit淺封裝
本文受啓發於Retrofit 2 — How to Send Plain Text Request Body, 在此表示感謝。Retrofit官方入門教程雖不能教你實現自己的封裝,但是對普通的使用有很好的示例作用。