这个题目看起来很有档次!有木有,好吧,先来一波词解释
(以下解释,多为百度,稍微有一点自己的理解,看客可以选择性跳过)
Retrofit2.0 :和Java领域的ORM概念类似, ORM把结构化数据转换为Java对象,而Retrofit 把REST API返回的数据转化为Java对象方便操作。同时还封装了网络代码的调用。以下为个人理解:retrofit 这个玩意吧,首先是个用来进行网络请求,然后,retrofit内部是希望完成发起请求到生成bean的过程。最后,配合RxJava口味更加。这里提一句,如果没有使用RxJava,咱项目还使用Okhttp吧,没必要自己为难自己。
非Restful API :这里没百度到。还是举个粟子吧,糖炒的,拿这次的接口来说,请求城市列表,我所需要的正确的数据
[
{
"cityid": "1",
"parentid": "0",
"citycode": "101010100",
"city": "北京"
},
{
"cityid": "24",
"parentid": "0",
"citycode": "101020100",
"city": "上海"
}
]
以上是Reetful APT ,但是我们现在大部分用到的数据是:
{
"status": "0",
"msg": "ok",
"result":
[
{
"cityid": "1",
"parentid": "0",
"citycode": "101010100",
"city": "北京"
},
{
"cityid": "24",
"parentid": "0",
"citycode": "101020100",
"city": "上海"
}
]
}
这样数据,加入了statust状态与msg ,这样可以方便让我们做一些事情,哪一些事情?反正不是嘿嘿的事情,理论上,开始跟后台商(p)量(y)好,后台给你反的数据应该是保持这样的
{
"status": "0",
"msg": "ok",
"result": "主要数据"
}
这种便是非Restful API的基本情况
Apt: APT(Annotation Processing Tool)是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。 Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件。
随着Android Gradle 插件 2.2 版本的发布,Android Gradle 插件提供了名为 annotationProcessor 的功能来完全代替 android-apt ,自此android-apt 作者在官网发表声明证实了
后续将不会继续维护 android-apt ,并推荐大家使用 Android 官方插件annotationProcessor.
Apt 个人理解,本人也是第一次接触Apt,本次也算试手,apt 对于我来说,就是用注释生成一些脑残代码。所谓脑残,就是一些有规律的代码。比如通过Swtich 语句返回不同的Converter,这个往下看就能看到了
Converter :英文为转换器,在retrofit的使用中,Converter的作用,就是将返回的数据,进行解析,生成你想要的数据。Converter的实体化是是通过工厂模式,本人常用GsonResponseBodyConverter为官方提供,but,这个Converter只是用来Restful能用。。。也就是说,基本是没有什么项目会使用,二次but,本人的Converter的基本是模仿官方,还是有用的~~
-----------------------------------------以下是重点----------------------------------
对于Converter基本使用,我还是推荐如何使用Retrofit请求非Restful API, 这里重点是为Converter的生成方式加入APT,说明一下使用情况,就是跟后台锅锅没有商量好,
每一个接口的解析过程不能用通用的解析过程。也就是说,需要的新的Converter。这时候,翠花,上菜,呸!上接口!
@GET("weather/city")
Observable<ArrayList<CityBean>> getAllCity();
@GET("weather/query")
Observable<CityWeatherBean> getCityWeatherService(@Query("city") String city, @Query("citycode") String citycode, @Query("cityid") String cityid);
我们假定,getAllCity,与getCityWeatehrerSercice,并不是一种数据格式,分别需要DefaultConverter与SpicalConverter两个解析类来解析。而项目中的使用情况为,Retrofit为单例,通过addConverterFactory加入工厂, ConverterFactory的方法responseBodyConverter(Type,Annotation[],retrofit)来生成Converter,
这时,我们机会来了,请盯紧我们的方法中第二个参数,这是一个注解的集合,那么这个集合是怎么来的?怎么来的我还真是不知道,but,我知道集合有接口请求的注解(我怎么
知道的?上个文章里面有介绍。。。),那么,也就是说,我们也可以写一个注解,标识在上面,让Retrofit来获得,那么,这样可以让工厂通过这个标识,来生成相应的Converter,
说干就干。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ConverterInstance {
Class value();
}
稍微解释一下这个注解,@target这个表示用在方法之上,@Retention RUNTIME 注解会在class字节码文件中存在,在运行时可以通过反射获取到,value()方法,使用时
需要指定一个类,这个,我们的注解就可以使用了。放到我们的接口上
@ConverterInstance(DefualtConverter.class)
@GET("weather/city")
Observable<ArrayList<CityBean>> getAllCity();
这样,ConverterFactory便可以得到相应的数据了。
for (Annotation a : annotations) {
if (a instanceof ConverterInstance) {
Class c = ((ConverterInstance) a).value();
//实例化过程
break;
}
}
这时候,比较熟悉java的知道,既然知道了Class,可以通过反射来new ,反射的问题,一直都被人讨论,就算是性能低下,但我们也没有停止使用,但是今天,我们并不需要
反射。那么问题来了,怎么直接new 这个类呢。说一个比较的傻的做法,自己写Swtich语句~~
public static AbstractConverter create(Class mClass) {
switch (mClass.getSimpleName()) {
case "DefualtConverter":
return new DefualtConverter();
case "SpecialConvert":
return new SpecialConvert();
default:
return new DefualtConverter();
}
}
看起来还不错,起码项目应该能运行,但是,问题也来了,两个也好写,如果多了呢,不多说,10个,写的时候,你会不会在想,这么脑残的设计,谁想的。。。是不是宁愿用
反射。当你有这种想法的时候,APT出现了,踩着七彩祥云来拯救世界了。我们利用APT,生成这种所谓的脑残代码,解放我们自己的思路。这里我们上一下主要的代码
/**
* 生成NewConverter
*/
private void onConverter() {
//类名
String Class_Name = "NewConverter";
//类设定 public final class NewConverter
TypeSpec.Builder tb = classBuilder(Class_Name)
.addModifiers(PUBLIC, FINAL)
.addJavadoc("by Apt,用来返回一些特别的Converter 生成代码见apt 中的AnnotationProcessor nnConverter() \n")
.addJavadoc("为什么不用@link...因为用了也不管用 \n");
//方法设定 public static AbstractConverter create(Class mClass)
MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("create")
.addJavadoc("by apt \n")
.returns(ClassName.get("com.yu.zz.retrofitapt.Retrofit", "AbstractConverter"))
.addModifiers(PUBLIC, STATIC)
.addParameter(Class.class, "mClass");
//switch 语句
CodeBlock.Builder blockBuilder = CodeBlock.builder();
//括号开始
blockBuilder.beginControlFlow(" switch (mClass.getSimpleName())");
ArrayList<ClassName> names = new ArrayList<>();
for (Element element : roundEnv.getElementsAnnotatedWith(ConverterInstance.class)) {
ClassName className = null;
try {
Class currentType = element.getAnnotation(ConverterInstance.class).value();
className = ClassName.get(currentType);
} catch (MirroredTypeException mte) {
DeclaredType classTypeMirror = (DeclaredType) mte.getTypeMirror();
TypeElement classTypeElement = (TypeElement) classTypeMirror.asElement();
className = ClassName.get(classTypeElement);
}
//Case 语句:case 所列举的不能有重复,加入一层list的判断:
if (!names.contains(className)) {
names.add(className);
blockBuilder.addStatement("case $S: \n return new $T()", className.simpleName(), className);
}
}
//swtich default语句,返回默认的Converter
blockBuilder.add("default: \n return new $T();\n", ClassName.get("com.yu.zz.retrofitapt.Retrofit", "DefualtConverter"));
//括号线束
blockBuilder.endControlFlow();
//方法中加入代码
methodBuilder.addCode(blockBuilder.build());
//类中加入方法
tb.addMethod(methodBuilder.build());
// 生成源代码
JavaFile javaFile = JavaFile.builder("com.apt", tb.build()).build();
try {
javaFile.writeTo(mFiler);
} catch (IOException e1) {
e1.printStackTrace();
}
}
上面的生成方法,引用了三方库javapoet。
下面看一下我们的生成代码
package com.apt;
import com.yu.zz.retrofitapt.Retrofit.AbstractConverter;
import com.yu.zz.retrofitapt.Retrofit.DefualtConverter;
import com.yu.zz.retrofitapt.Retrofit.SpecialConvert;
/**
* by Apt,用来返回一些特别的Converter 生成代码见apt AnnotationProcessor OnConverter
* 为什么不用@link...因为用了也不管用
*/
public final class NewConverter {
/**
* by apt1
*/
public static AbstractConverter create(Class mClass) {
switch (mClass.getSimpleName()) {
case "DefualtConverter":
return new DefualtConverter();
case "SpecialConvert":
return new SpecialConvert();
default:
return new DefualtConverter();
}
}
}
这里,我复制了全部,包括package与iimport ,只是为了证明,这是些都是自动生成。这个Class是没问题的。
完成的APT,后,能过ReBuild的项目,我的代码就可以在项目中直接调用,这时候,更新我们的ConverterFactory
更新后的ConverterFactory
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
AbstractConverter<?> converter = null;
// DefualtConverter converter = new DefualtConverter();
// converter.setAdapter(adapter);
//找到方法中的所有注解,找到我们自定义的ConverterInstance
for (Annotation a : annotations) {
if (a instanceof ConverterInstance) {
Class c = ((ConverterInstance) a).value();
converter = NewConverter.create(c);
break;
}
}
//如果没有标明用什么Converter ,生成默认的Converter
if (null == converter)
converter = new DefualtConverter();
converter.setAdapter(adapter);
return converter;
}
到这,是不是觉得一脸懵逼,但是,我们的注释已经开始愉快的使用了。再也不怕后台妖孽了。(至少,我还没有碰到~~哈哈)。
ps:github :https://github.com/yehengzhishang/RetrofitAPT 。
ps2.0:在MaInAcitiy中加入了注释,为项目构建过程,在相应地方也加入了注释
还是来个例子
/**
* step 1 新建一个project (加入联网权限,以及为Layout的设定)
* <p>
* step 2 gradle app 导入我们需要的三方数据
* <p>
* step 3 开始写网络请求(本次网络接口,用的阿里云的免费天气接口,为什么用这个,,,因为是免费的)
* 3.1 写出实体bean {@link CityBean,com.yu.zz.retrofitapt.Bean.CityWeatherBean}
* 3.2 写出rerforit 所需interface {@link com.yu.zz.retrofitapt.API.WeatherService}
* 3.3 对于API 的封装 {@link com.yu.zz.retrofitapt.API.Api}
* <p>
* step 4 对于Converter第一次 代码设计
* 4.1 通用的Converter {@link com.yu.zz.retrofitapt.Retrofit.DefualtConverter}
* 4.2 ConverterFactory {@link com.yu.zz.retrofitapt.Retrofit.DefualtConverterFactory}
* <p>
* step 5 接口调试 (项目准备了两个接口,但是实际测试目前为止,只试过一个)
* 5.1 recyclerview Adapter {@link CityAdapter}
* 5.2 数据调试 {@link #getNetData()}
* <p>
* step 6. 加入apt ,生成{@link MyApiFactory}
* 6.1 新建 module :lib 新建注解 {@link com.zz.yu.lib.ApiFactory}
* 6.2 新建 module :apt (要选择 java library ,并且对gradle :apt进行三方库的引入)
* 6.3 apt 新建Processor (AnnotationProcessor) 代码设计 onApi()
* 6.4 加入注解 {@link com.yu.zz.retrofitapt.API.WeatherService} ApiFactory
* 代码替换 {@link #getNetData()}
* <p>
* step 7 利用Apt 生成 {@link com.apt.NewConverter}
* 7.1 lib 新建注解 {@link com.zz.yu.lib.ConverterInstance}
* 7.2 Converter更改 {@link com.yu.zz.retrofitapt.Retrofit.DefualtConverter}
* 新增{@link com.yu.zz.retrofitapt.Retrofit.AbstractConverter}
* 新增 apt AnnotationProcessor 中加入 onConverter()
* 7.3 {@link WeatherService#getAllCity()} 加入注解
* 7.4 更改 {@link com.yu.zz.retrofitapt.Retrofit.DefualtConverterFactory } 逻辑
*/
public class MainActivity extends AppCompatActivity {
代码中相应的提示
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type,
Annotation[] annotations,
Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
AbstractConverter<?> converter = null;
/*------------------step 4.2 始-------------------*/
// DefualtConverter converter = new DefualtConverter();
// converter.setAdapter(adapter);
/*------------------step 4.2 终-------------------*/
/*------------------step 7.4 始-------------------*/
//找到方法中的所有注解,找到我们自定义的ConverterInstance
for (Annotation a : annotations) {
if (a instanceof ConverterInstance) {
Class c = ((ConverterInstance) a).value();
converter = NewConverter.create(c);
break;
}
}
//如果没有标明用什么Converter ,生成默认的Converter
if (null == converter)
converter = new DefualtConverter();
converter.setAdapter(adapter);
/*------------------step 7.4 终-------------------*/
return converter;
}
用 step +始或终标识,表示设计过程。方便理解
ps3.0 感谢 项目T mvp作者 North_2016 的支持 以及各类博客作者,太多,不一一列举,如有侵权,请通知我,我立即删除。