团队并行开发,每个人对自己模块的api进行封装,
public interface UserAPI {
@POST("/mobile/settings/login.html")
@FormUrlEncoded
Flowable doLogin(@QueryMap Map map);
@POST("/mobile/settings/logout.html")
@FormUrlEncoded
Flowable doLogout();
}
public interface IRetrofitWeather {
/**
* retrofit 封装
* @param location
*/
@FormUrlEncoded
@POST("telematics/v3/weather?")
Call getWeather(@Field("location") String location,
@Field("output") String ouput,
@Field("ak") String ak);
}
@Override
public void getWeather(String location, Callback callback) {
IRetrofitWeather api = retrofit.create(IRetrofitWeather.class);
Call 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 login(String username, String password, Map map) {
return Api.getInstance().retrofit.create(com.jason.UserService.class).login(username,password,map).compose(RxSchedulers.io_main());
}
public static Flowable getWeather(String location, Map 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());
})
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 login(String username, String password, Map map) {
return OkHttpClient.getInstance().retrofit.create(com.jason.UserService.class).login(username,password,map).compose(RxSchedulers.io_main());
}
public static Flowable getWeather(String location, Map map) {
return OkHttpClient.getInstance().retrofit.create(com.jason.WeatherService.class).getWeather(location,map).compose(RxSchedulers.io_main());
}
}
利用APT的方式,我们生成HttpClient的方式免去了多人去修改工厂类的情况,这种方式由于编译时需要遍历的关系,编译时会慢一点。
感谢North文章的帮助
http://www.jianshu.com/p/dca3e2c8608a