團隊并行開發,每個人對自己子產品的api進行封裝,
public interface UserAPI {
@POST("/mobile/settings/login.html")
@FormUrlEncoded
Flowable<UserEntity> doLogin(@QueryMap Map<String, Object> map);
@POST("/mobile/settings/logout.html")
@FormUrlEncoded
Flowable<Boolean> doLogout();
}
public interface IRetrofitWeather {
/**
* retrofit 封裝
* @param location
*/
@FormUrlEncoded
@POST("telematics/v3/weather?")
Call<WeatherApiData> getWeather(@Field("location") String location,
@Field("output") String ouput,
@Field("ak") String ak);
}
然後利用Retrofit的create方法建立出對應的apiservice進行網絡請求,各個子產品都需要含有apiservice執行個體的簡單單例封裝,那麼多個子產品就有多個單例,這個時候就需要工廠模式進行設計。
@Override
public void getWeather(String location, Callback<WeatherApiData> callback) {
IRetrofitWeather api = retrofit.create(IRetrofitWeather.class);
Call<WeatherApiData> call = api.getWeather(location, APIConstant.URL.OUTPUT, APIConstant.URL.AK);
call.enqueue(callback);
}
如果子產品需要調用User子產品的接口時,就會有很麻煩。而且不可避免的抽象工廠需要設計多個抽象類和方法,使得設計非常繞,層次多,類多。那麼我們利用APT(Annotation Processing Tool)機制,動态的生成HttpClient可以解決以上問題。
@HttpClient
public interface UserAPI
首先,我們在每個需要進行網絡調用的api加上@HttpClient标簽,
public final class HttpClient {
/**
* @created by apt
*/
public static Flowable<LoginEntity> login(String username, String password, Map<String, Object> map) {
return Api.getInstance().retrofit.create(com.jason.UserService.class).login(username,password,map).compose(RxSchedulers.io_main());
}
public static Flowable<WeatherEntity> getWeather(String location, Map<String, Object> map) {
return Api.getInstance().retrofit.create(com.jason.WeatherService.class).getWeather(location,map).compose(RxSchedulers.io_main());
}
}
在編譯時系統HttpClientProccessor運作時會自動生成HttpClient類,并且各個子產品的api方法都會在HttpClient中生成,HttpClient中封裝了Retrofit通用單例和Rxjava的通用部分,免去了上面封裝需要的callback。
HttpClient.login(username, pwd, defaultMap)
.subscribe(loginEntity -> {
Log.i("LoginPresenter", "onNext userEntity:"+loginEntity);
getView().loginSuccess(loginEntity);
}, throwable -> {
Log.i("LoginPresenter", "error msg:"+throwable.toString());
})
各個子產品使用時可直接使用HttpClient中的public靜态方法,Rxjava免去了我們去寫另外一個包含callback或listener的接口,也就不需要工廠類做解耦設計。
public class HttpClientProcessor implements IProcessor {
@Override
public void process(RoundEnvironment roundEnv, AnnotationProcessor mAbstractProcessor) {
String CLASS_NAME = "HttpClient";
TypeSpec.Builder tb = classBuilder(CLASS_NAME).addModifiers(PUBLIC, FINAL).addJavadoc("@API factory created by apt");
try {
for (TypeElement element : ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(HttpClient.class))) {
mAbstractProcessor.mMessager.printMessage(Diagnostic.Kind.NOTE, "正在處理: " + element.toString());
for (Element e : element.getEnclosedElements()) {
ExecutableElement executableElement = (ExecutableElement) e;
MethodSpec.Builder methodBuilder =
MethodSpec.methodBuilder(e.getSimpleName().toString())
.addJavadoc("@created by apt")
.addModifiers(PUBLIC, STATIC);
methodBuilder.returns(TypeName.get(executableElement.getReturnType()));
String paramsString = "";
for (VariableElement ep : executableElement.getParameters()) {
methodBuilder.addParameter(TypeName.get(ep.asType()), ep.getSimpleName().toString());
paramsString += ep.getSimpleName().toString() + ",";
}
methodBuilder.addStatement(
"return $T.getInstance()" +
".service.$L($L)" /*+
".compose($T.io_main())"*/
, ClassName.get("com.jason.api", "OkHttpClient")
, e.getSimpleName().toString()
, paramsString.substring(0, paramsString.length() - 1)
tb.addMethod(methodBuilder.build());
}
}
JavaFile javaFile = JavaFile.builder(Utils.PackageName, tb.build()).build();// 生成源代碼
javaFile.writeTo(mAbstractProcessor.mFiler);// 在 app module/build/generated/source/apt 生成一份源代碼
} catch (FilerException e) {
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
HttpClientProccessor的代碼,利用AOP 切片程式設計的思想,在編譯時去周遊所有Java檔案,包含@HttpClient注解的類的方法,都會引入到新生成的HttpClient這個類中。
public final class HttpClient {
/**
* @created by apt
*/
public static Flowable<LoginEntity> login(String username, String password, Map<String, Object> map) {
return OkHttpClient.getInstance().retrofit.create(com.jason.UserService.class).login(username,password,map).compose(RxSchedulers.io_main());
}
public static Flowable<WeatherEntity> getWeather(String location, Map<String, Object> map) {
return OkHttpClient.getInstance().retrofit.create(com.jason.WeatherService.class).getWeather(location,map).compose(RxSchedulers.io_main());
}
}
Api是對對各個子產品的通用的Retrofit serviceApi,我們看到HttpClient将Weather和User的接口都加入進來,所有接口都在HttpClient中,HttpClient是自動生成,
利用APT的方式,我們生成HttpClient的方式免去了多人去修改工廠類的情況,這種方式由于編譯時需要周遊的關系,編譯時會慢一點。
感謝North文章的幫助
http://www.jianshu.com/p/dca3e2c8608a