引言
之前看北京GDG直播收获颇丰,我打算用Github API来实践一下Piasy提出的完美model,这是这个系列的第一篇,时下非常流行apt生成代码,大家喜闻乐见的ButterKnife就是一个典型的例子,Google出品的AutoValue也是其中的翘楚,希望能通过这篇文章让你了解AutoValue。
github
在这个小项目中我将实践这个系列文章的所有技术,正在持续更新。
https://github.com/Bigmercu/PerfectModel
欢迎star fork issue
AutoValue
引用一段话来说明它的作用
“AutoValue is a great tool for eliminating the drudgery of writing mundane value classes in Java. It encapsulates much of the advice in Effective Java Chapter 2, and frees you to concentrate on the more interesting aspects of your program. The resulting program is likely to be shorter, clearer, and freer of bugs. Two thumbs up.”
– Joshua Bloch, author, Effective Java
这个大哥是Effective Java
的作者,大大的有名啊,这段话大概说的是 AutoValue
是一个非常棒的工具,它可以减少在Java里写很多重复的代码。这让你可以专注于程序中有趣的部分,它可以让你的代码更简短清晰,几乎没有bug。
less code其实是很有意义的,写的代码越少,自然出现bug的几率就越少。而AutoValue使用apt的方式来自动生成的代码没有bug,可以减少大量重复的工作,其实我们之前就在这么做了,比如IDE就自带了 getter 和 setter 生成等等。
那么它到底能做什么呢?
AutoValue可以用来生成实体。
一个我们熟悉的Entry可能包括哪些部分?
o Field
o getter()
o setter()
o equals()
o hashCode()
o null检查
o toString()
o 构造方法
它还支持不限于
o Gson解析支持->[auto-value-gson]
o Parcelable支持->[auto-value-parcel]
o 简化和数据库交互->[sqldelight]
这些它都能做到(或者通过附加插件),并且大部分代码都不需要你手写了,想想就很美好啊TT。
怎么编写一个entry
首先 build.gradle script中插入:
1 2 3 4 | dependencies { compileOnly "com.google.auto.value:auto-value:1.2" apt "com.google.auto.value:auto-value:1.2" } |
o 用@AutoValue
修饰类
o 将类加上修饰abstract
o 使用这样的形式来加入元素
1 2 | abstract String name(); abstract int numberOfLegs(); |
它默认包括:
o getter()
o setter()
o equals()
o hashCode()
o null检查
o toString()
o 构造方法
小tip
我们一般都会使用GsonFormater
来格式化JSON数据,完事以后要修改成上面的形式可以有个小技巧。
首先修改前面的public
为abstract
我只知道MAC的快捷键,Windows的同学自己发掘一下。
o 首先按住super键,把数遍放在public之前往下拖,就会得到多个光标,都在public之前
再往右拖,就能选中多个public了
o 键入abstract
完成第一步,完事以后要在变量名后面加上括号,可以这么做:
按住super往右下角拖,选中所有要修改的行,并且保证光标在冒号后面
按一下方向右键,会退出选中状态,光标仍然在最后,再按一下左,光标来到每个变量名后面,这时键入()
就可以了。
按一下ESC可以退出多行编辑
注意事项
o 在auto修饰的实体里,不要写包括但不限于 equals()/hashcode()/tostring()
等等方法,因为都会自动生成了。
o 要注意,如果元素可以为null,要使用@Nullable
修饰,因为Autovalue会默认为所有没有@Nullable
修饰的元素都生成null判断,一旦是null就会抛出NullPointerException(我被坑了这里)。
o 仍然可以使用@SerializedName()
o 如果有嵌套的类,也都一并要用 abstract修饰
最后的样子大概就是这样
其中的TypeAdapter
后面会说。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | @AutoValue public abstract class SearchEntry { @SerializedName("total_count") abstract int total_count(); @SerializedName("incomplete_results") abstract boolean incomplete_results(); abstract String name(); abstract int id(); abstract List<ItemsBean> items(); @AutoValue public abstract static class ItemsBean { abstract int id(); abstract String name(); @Nullable abstract String full_name(); abstract OwnerBean owner(); @SerializedName("private") abstract boolean privateX(); ... @AutoValue public abstract static class OwnerBean { abstract String login(); abstract int id(); @Nullable abstract String avatar_url(); ... @Nullable abstract String type(); abstract boolean site_admin(); public static TypeAdapter<OwnerBean> typeAdapter(Gson gson) { return new AutoValue_SearchEntry_ItemsBean_OwnerBean.GsonTypeAdapter(gson); } } public static TypeAdapter<ItemsBean> typeAdapter(Gson gson) { return new AutoValue_SearchEntry_ItemsBean.GsonTypeAdapter(gson); } } public static TypeAdapter<SearchEntry> typeAdapter(Gson gson) { return new AutoValue_SearchEntry.GsonTypeAdapter(gson); } } |
加入Builder支持
没用过Builder的同学可能会有点疑问,Builder可以干啥,看代码
1 2 3 4 | Animal dog = Animal.builder() .setName("dog") .setNumberOfLegs(4) .build(); |
类似这样,可以创建一个对象。
Cook 步骤:
o 编写builder()方法,返回new AutoValue_*.Builder();
具体根据你的实体名字修改
o 编写Builder类:
o 使用@AutoValue.Builder
注解abstract static class Builder
类
o 在类中必须要有一个方法abstract T build();
将T改为你的实体。
o 在类中用abstract Builder
变量名
(
变量类型
value)
这样的形式声明你所有的参数。
最后类似下面:
1 2 3 4 5 6 7 8 9 10 | static Builder builder() { return new AutoValue_Animal.Builder(); } @AutoValue.Builder abstract static class Builder { abstract Builder name(String value); abstract Builder numberOfLegs(int value); abstract Animal build(); } |
当然用法不仅于此,更多高级用法可以参考这篇Builder文档
auto-value-gson
这个AutoValue插件是用来生成GsonTypeAdapterFactory
的,和大家熟知的Gson create方法不太一样,使用这个插件以后就可以这么实例化:
1 | Gson mGson = new GsonBuilder().registerTypeAdapterFactory(MyAdapterFactory.create()).create(); |
在entry中加入typeAdapter方法
上面已经贴了代码了,一般形式
1 2 3 | public static TypeAdapter<T> typeAdapter(Gson gson) { return new AutoValue_T.GsonTypeAdapter(gson); } |
T 就是类名了,如果有内部嵌套的类,每个类都要写!
如果在这个过程中有错误提示之类的不要管,把代码敲上去以后rebuild一下就好了。
这样我们就能获得每个类的typeAdapter
了,再创建一个方法来返回TypeAdapterFactory
1 2 3 4 5 6 | @GsonTypeAdapterFactory public abstract class MyAdapterFactory implements TypeAdapterFactory { public static TypeAdapterFactory create() { return new AutoValueGson_MyAdapterFactory(); } } |
AutoValueGson_MyAdapterFactory
中都做了啥?
就是根据类来返回对应的typeadapter,看到类似AutoValueGson_
这样的类都是Autovalue生成的,不用我们写了。
得到TypeAdapterFactory
以后我们就可以创建Gson对象了,有了Gson对象就可以解析JSON了。
1 2 | SearchEntry mSearchEntry; mSearchEntry = mGson.fromJson(str.toString(), SearchEntry.class); |
AutoValue的强大之处不仅于此,序列化也有序列化插件auto-value-parcel,这个比较简单,有需要自己看看官方文档咯.
共同学习,写下你的评论
评论加载中...
作者其他优质文章