Retrofit--合理封裝回調能讓你的專案高逼格
本文已授權微信公眾號:鴻洋(hongyangAndroid)在微信公眾號平臺原創首發。
緒論
前面我們討論了使用Retrofit時怎樣去設定OKHttp,包括持久化管理Cookie、設定網路超時、設定列印攔截器、設定快取、Header等等,詳細可檢視
Retrofit–使用Retrofit時怎樣去設定OKHttp
Retrofit+OKHttp 教你怎麼持久化管理Cookie
今天我們討論的主題是怎麼封裝回調才能完美的適應自己的需求。我們都知道程式碼風格是每個人都有自己的風格,不可能完全一樣,那麼我們寫出來的程式碼怎樣能夠儘可能的去滿足需求呢?換句話說怎樣才能設計出高可用、高解耦、高可維護的程式碼架構呢?其實本人也是渣渣一個,看了一些別人的程式碼再加上自己的理解,今天把自己在用Retrofit時的一些想法分享給大家。
封裝背景:
在開始用Retrofit的時候在網上一搜,搜出來好多教程,而且口碑很好,所以我打算新的專案由原來的Xutils框架轉戰Retrofit。
Retrofit和Java領域的ORM概念類似, ORM把結構化資料轉換為Java物件,而Retrofit 把REST API返回的資料轉化為Java物件方便操作。同時還封裝了網路程式碼的呼叫。
看了一些資料後大致瞭解到,Retrofit 2.0利用註解的形式將我們訪問伺服器的URL以及引數封裝成了java物件,而OKHttp依舊去執行網路請求。現在網上的教程一般都告訴我們了怎樣去使用Retrofit(隨意找了一個教程):
1.首先定義一個介面:
public interface APIService {
@GET("/users/{user}/repos")
List<Repo> listRepos(@Path("user") String user);
}
2.接著通過Retrofit.Builder()去建立這個url以及引數
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("xxx")
.addConverterFactory(GsonConverterFactory.create())
.build ();
APIService service = retrofit.create(APIService.class);
3.最後通過定義Call去執行網路請求
Call<User> call = apiService.getUser(username);
call.enqueue(new Callback<User>() {
@Override
public void onResponse(Response<User> response) {
int statusCode = response.code();
User user = response.body();
}
@Override
public void onFailure(Throwable t) {
// Log error here since request failed
}
});
然後我們就能在網路請求成功失敗的回調出去更新UI了。
自定義響應體CallModel
很簡單的實現了一個網路請求,當然我在剛開始的時候一直也都是這麼使用的,因為Retrofit自己封裝了JSON解析的過程,我們只需在建造Retrofit的時候加入addConverterFactory(GsonConverterFactory.create())
就可以了,但是得保證我們定義的API介面的時候Call裡面的bean要和伺服器返回的介面一一對應,否則這個欄位就會為null,甚至網路請求失敗報錯json轉化異常。
我們都知道伺服器返回的結果一般都是下面這種格式的:
一定是有code狀態碼和返回資訊的,我之前的用法和教程一樣,說將伺服器返回的結果複製下來直接在AS上面利用GsonFormat轉化就OK了,確實很方便,但是這樣下來每個bean裡面都會有重複的erroe_code和message或者伺服器返回其他,所以我是這樣做的:
public class BaseCallModel<T> {
public int errno;
public String msg;
public T data;
}
定義一個BaseCallModel,利用泛型去適合伺服器返回的所有的bean,而你在定義一個API介面的時候就可以這樣定義:
@GET("user/login")
Call<BaseCallModel<User>> doLogin(@Query("email") String email, @Query("password") String pwd);
自定義CallBack
自定義完響應體之後,那麼問題又來了,error_code會有不同的值,而不同的值需要我們所做的操作不同,舉個例子,我們的需求是
- 0-請求成功
- 1-請求失敗,登入過期
- 2-請求失敗,無許可權
- 3-請求失敗-餘額不足
- ….
假如登入過期需要我們重新登入,跳轉到登入介面的話,我們不可能在每個網路請求的回撥裡面都去判斷error_code吧?那樣豈不是很….,所以就有了它:
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Created by Hankkin on 2016/6/4.
*/
public abstract class MyCallback<T extends BaseCallModel> implements Callback<T> {
@Override
public void onResponse(Call<T> call, Response<T> response) {
if (response.raw().code() == 200) {//200是伺服器有合理響應
if(response.body().errno == 0){
onSuc(response);
}
else if (response.body().errno == 1){
}
else if (response.body().errno == 2){
onAutoLogin();
}
else if (){
}
.
.
.
else {
onFail(response.body().msg);
}
} else {//失敗響應
onFailure(call, new RuntimeException("response error,detail = " + response.raw().toString()));
}
}
@Override
public void onFailure(Call<T> call, Throwable t) {//網路問題會走該回調
if(t instanceof SocketTimeoutException){
//
}else if(t instanceof ConnectException){
//
}else if(t instanceof RuntimeException){
//
}
onFail(t.getMessage());
}
public abstract void onSuc(Response<T> response);
public abstract void onFail(String message);
public abstract void onAutoLogin();
}
我自定義了一個抽象類實現了Retrofit的CallBack<>,OnResponse()方法裡面去判斷網路請求正常的各種情況,onFailure()方法裡面則是網路有問題會走該回調。而OnResponse()回撥中也有可能網路請求失敗,根據response.raw().code()去判斷;然後你也可以根據異常出現的狀況去執行不同的UI,例如:
if(t instanceof SocketTimeoutException){
//
}else if(t instanceof ConnectException){
//
}else if(t instanceof RuntimeException){
//
}