[置顶] Android 利用APT对网络请求进行极简封装
2017-08-17 00:38
856 查看
团队并行开发,每个人对自己模块的api进行封装,
然后利用Retrofit的create方法创建出对应的apiservice进行网络请求,各个模块都需要含有apiservice实例的简单单例封装,那么多个模块就有多个单例,这个时候就需要工厂模式进行设计。
如果模块需要调用User模块的接口时,就会有很麻烦。而且不可避免的抽象工厂需要设计多个抽象类和方法,使得设计非常绕,层次多,类多。那么我们利用APT(Annotation Processing Tool)机制,动态的生成HttpClient可以解决以上问题。
首先,我们在每个需要进行网络调用的api加上@HttpClient标签,
在编译时系统HttpClientProccessor运行时会自动生成HttpClient类,并且各个模块的api方法都会在HttpClient中生成,HttpClient中封装了Retrofit通用单例和Rxjava的通用部分,免去了上面封装需要的callback。
各个模块使用时可直接使用HttpClient中的public静态方法,Rxjava免去了我们去写另外一个包含callback或listener的接口,也就不需要工厂类做解耦设计。
HttpClientProccessor的代码,利用AOP 切片编程的思想,在编译时去遍历所有Java文件,包含@HttpClient注解的类的方法,都会引入到新生成的HttpClient这个类中。
Api是对对各个模块的通用的Retrofit serviceApi,我们看到HttpClient将Weather和User的接口都加入进来,所有接口都在HttpClient中,HttpClient是自动生成,
利用APT的方式,我们生成HttpClient的方式免去了多人去修改工厂类的情况,这种方式由于编译时需要遍历的关系,编译时会慢一点。
感谢North文章的帮助
http://www.jianshu.com/p/dca3e2c8608a
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
相关文章推荐
- Android网络请求Retrofit进行二次封装,拿过来就能用
- 利用Fiddler对Android手机网络请求进行抓包
- [置顶] Android Kotlin 开发--偶遇Rxjava、Retrofit进行网络请求
- Android利用Fiddler进行网络数据抓包【怎么跟踪微信请求】
- 利用android自带http包进行网络请求
- [Android Pro] 利用tcpdump和wireshark对android网络请求进行分析
- Android网络请求框架----Okhttp3完全解析(2),封装框架
- Android RxJava+Retrofit+OkHttp深入浅出-终极封装二(网络请求)
- Android基于http封装的网络请求框架
- Android利用Fiddler进行网络数据抓包
- IOS开发之—— 在AFN基础上进行的网络请求的封装
- Android利用Fiddler进行网络数据抓包
- Android中利用httpclient进行网络通信的方法(以用户登录为例说明)
- 请求网络[置顶] Android网络请求库——android-async-http请求网络
- Android利用Fiddler进行网络数据抓包
- android 网络请求封装,可改
- Android中使用Volley开源库进行Http网络请求(POST方式)
- Swift-利用AFN封装网络请求
- Android 利用httpclient进行网络通信,实现用户登录的方法
- [置顶] 对AFN 进行进一步封装,再应用于具体的项目,这样可以将业务逻辑代码与网络框架进行解耦