一、什么是AutoValue
意思就是自动值,谷歌出品,添加@AutoValue
这样的注解 就能够自动生成代码,使得程序可能更短,更清晰。 支持Java1.6+
github: https://github.com/google/auto/blob/master/value/userguide/index.md
首先看一个bean类,User.java:
- public class User{
- private String name;
- private String addr;
- private int age;
- private String gender;
- private String hobby;
- private String sign;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- ....(太多就省略了)
- }
一堆的getter和setter代码很多,到时候添加toString
、hashCode
、equals
这些代码就更麻烦了(虽然ide有快速生成),这时候AutoValue就来拯救世界了。
二、基本使用
一步一脚印
2.1 导包
初次使用需要注意,官方只说了在module依赖,这样会build失败的,对于新手来说会一脸懵逼,因为需要apt。
项目的build.gradle添加依赖:
- dependencies {
- //添加这行
- classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
- }
在module的build.gradle依赖以下,当前最新是1.4.1
- //顶部添加
- apply plugin: 'com.neenbedankt.android-apt'
- dependencies {
- compile "com.google.auto.value:auto-value:1.4.1"
- apt "com.google.auto.value:auto-value:1.4.1"
- }
重新Sync即可
2.2 使用AutoValue标识bean
现在来重新编写User类:
- @AutoValue
- public abstract class User {
- abstract String name();
- abstract String addr();
- abstract int age();
- abstract String gender();
- abstract String hobby();
- abstract String sign();
- }
然后build -> make module一下,这时候就会生成AutoValue_User.java
,在build\generated\source\apt\debug\包名\AutoValue_User.java
里面的代码为:
- final class AutoValue_User extends User {
- private final String name;
- private final String addr;
- private final int age;
- private final String gender;
- private final String hobby;
- private final String sign;
- AutoValue_User(
- String name,
- String addr,
- int age,
- String gender,
- String hobby,
- String sign) {
- if (name == null) {
- throw new NullPointerException("Null name");
- }
- this.name = name;
- if (addr == null) {
- throw new NullPointerException("Null addr");
- }
- this.addr = addr;
- this.age = age;
- if (gender == null) {
- throw new NullPointerException("Null gender");
- }
- this.gender = gender;
- if (hobby == null) {
- throw new NullPointerException("Null hobby");
- }
- this.hobby = hobby;
- if (sign == null) {
- throw new NullPointerException("Null sign");
- }
- this.sign = sign;
- }
- @Override
- String name() {
- return name;
- }
- @Override
- String addr() {
- return addr;
- }
- @Override
- int age() {
- return age;
- }
- @Override
- String gender() {
- return gender;
- }
- @Override
- String hobby() {
- return hobby;
- }
- @Override
- String sign() {
- return sign;
- }
- @Override
- public String toString() {
- return "User{"
- + "name=" + name + ", "
- + "addr=" + addr + ", "
- + "age=" + age + ", "
- + "gender=" + gender + ", "
- + "hobby=" + hobby + ", "
- + "sign=" + sign
- + "}";
- }
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o instanceof User) {
- User that = (User) o;
- return (this.name.equals(that.name()))
- && (this.addr.equals(that.addr()))
- && (this.age == that.age())
- && (this.gender.equals(that.gender()))
- && (this.hobby.equals(that.hobby()))
- && (this.sign.equals(that.sign()));
- }
- return false;
- }
- @Override
- public int hashCode() {
- int h = 1;
- h *= 1000003;
- h ^= this.name.hashCode();
- h *= 1000003;
- h ^= this.addr.hashCode();
- h *= 1000003;
- h ^= this.age;
- h *= 1000003;
- h ^= this.gender.hashCode();
- h *= 1000003;
- h ^= this.hobby.hashCode();
- h *= 1000003;
- h ^= this.sign.hashCode();
- return h;
- }
- }
这个类就是生成的类,里面就帮你编写好了各种方法hashCode
、toString
、equals
、getter
和setter
等等。
2.3 构造方法
这时候构造方法利用自己写的一个方法来实现newAutoValue_User
,在User类里面添加create方法进行调用生成的AutoValue_User
,这时候bean的方法这样的:
- @AutoValue
- public abstract class User {
- abstract String name();
- abstract String addr();
- abstract int age();
- abstract String gender();
- abstract String hobby();
- abstract String sign();
- //创建User,内部调用的是AutoValue_User
- static User create(String name,String addr,int age,String gender,String hobby,String sign){
- return new AutoValue_User(name,addr,age,gender,hobby,sign);
- }
- }
2.4 使用
使用User.create方法即可创建对应User对象:
- public class MainActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- User user = User.create("天平","广东",21,"男","敲代码","没有个性签名");
- Log.e("@@", "onCreate: "+user.toString());
- }
- }
即可看到输出
- onCreate: User{name=天平, addr=广东, age=21, gender=男, hobby=敲代码, sign=没有个性签名}
三、扩展api
你以为AutoValue的功能就那么少吗 ? 错,他还有很多扩展api。
3.1 auto-value-parcel
当User需要实现Parcelable接口的时候,AutoValue也可以帮你搞定了。
在基本的使用基础上继续导包(当前最新是0.2.5):
github地址:https://github.com/rharter/auto-value-parcel
- apt 'com.ryanharter.auto.value:auto-value-parcel:0.2.5'
- // 需要自定义TypeAdapter就要导入
- compile 'com.ryanharter.auto.value:auto-value-parcel-adapter:0.2.5'
基本Parcelable
这时候把User实现接口即可:
- @AutoValue
- public abstract class User implements Parcelable{
- abstract String name();
- abstract String addr();
- abstract int age();
- abstract String gender();
- abstract String hobby();
- abstract String sign();
- static User create(String name,String addr,int age,String gender,String hobby,String sign){
- return new AutoValue_User(name,addr,age,gender,hobby,sign);
- }
- }
重新make一下moduel即可看到生成的AutoValue_User
继承的原来的$AutoValue_User
类,把Parcelable
需要实现的方法放在了AutoValue_User类:
- final class AutoValue_User extends $AutoValue_User {
- public static final Parcelable.Creator<AutoValue_User> CREATOR = new Parcelable.Creator<AutoValue_User>() {
- @Override
- public AutoValue_User createFromParcel(Parcel in) {
- return new AutoValue_User(
- in.readString(),
- in.readString(),
- in.readInt(),
- in.readString(),
- in.readString(),
- in.readString()
- );
- }
- @Override
- public AutoValue_User[] newArray(int size) {
- return new AutoValue_User[size];
- }
- };
- AutoValue_User(String name, String addr, int age, String gender, String hobby, String sign) {
- super(name, addr, age, gender, hobby, sign);
- }
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(name());
- dest.writeString(addr());
- dest.writeInt(age());
- dest.writeString(gender());
- dest.writeString(hobby());
- dest.writeString(sign());
- }
- @Override
- public int describeContents() {
- return 0;
- }
- }
其他类型Parcelable
Parcel 这个扩展支持Parcel类支持的所有类型,但有时您可能需要parcel其他类型,如SparseArray或ArrayMap。您可以使用自定义TypeAdapter执行此操作(需要导入auto-value-parcel-adapter)
例如User里面有一个类型Date。这时候需要为Date定义一个TypeAdapters:
- public class DateTypeAdapter implements TypeAdapter<Date> {
- public Date fromParcel(Parcel in) {
- return new Date(in.readLong());
- }
- public void toParcel(Date value, Parcel dest) {
- dest.writeLong(value.getTime());
- }
- }
然后User添加Date类型:
- @AutoValue
- public abstract class User implements Parcelable{
- abstract String name();
- abstract String addr();
- abstract int age();
- abstract String gender();
- abstract String hobby();
- abstract String sign();
- //需要注解自定义的TypeAdapter
- @ParcelAdapter(DateTypeAdapter.class)
- public abstract Date date();
- static User create(String name,String addr,int age,String gender,String hobby,String sign,Date date){
- return new AutoValue_User(name,addr,age,gender,hobby,sign,date);
- }
- }
这里为延迟数据传递,新建一个SecondActivity,在MainActivit传递user过去
MainActivity.java
- public class MainActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- User user = User.create("天平","广东",21,"男","敲代码","没有个性签名",new Date());
- startActivity(new Intent(this,SecondActivity.class).putExtra("bean",user));
- }
- }
SecondActivity.java
- public class SecondActivity extends Activity {
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- User user = getIntent().getParcelableExtra("bean");
- Log.e("@@two", "onCreate: "+user.toString());
- }
- }
即可看到输出:
- E/@@: onCreate: User{name=天平, addr=广东, age=21, gender=男, hobby=敲代码, sign=没有个性签名, date=Mon Mar 13 14:36:19 GMT+08:00 2017}
3.2 auto-value-gson
就是你的用了AutoValues来修饰定义了Bean对象,Gson的就不能按照平常的方式来解析了,需要改变一下。
普及知识:
auto-value-gson 的github地址: https://github.com/rharter/auto-value-gson
导包(当前最新是0.4.6,注意,使用需要Gson,就是也要有Gson的包存在)
- apt 'com.ryanharter.auto.value:auto-value-gson:0.4.6'
- provided 'com.ryanharter.auto.value:auto-value-gson:0.4.6'
- compile 'com.google.code.gson:gson:2.8.0'
3.2.1 在Bean类添加TypeAdapter
Gson解析AutoValue修饰的对象,
这时候User是这样的:
- @AutoValue
- public abstract class User implements Parcelable{
- abstract String name();
- abstract String addr();
- abstract int age();
- abstract String gender();
- abstract String hobby();
- abstract String sign();
- //需要注解自定义的TypeAdapter
- @ParcelAdapter(DateTypeAdapter.class)
- public abstract Date date();
- //添加一个TypeAdapter<User>,这个TypeAdapter是Gson包里面的。
- public static TypeAdapter<User> typeAdapter(Gson gson){
- // AutoValue_User.GsonTypeAdapter 需要先make一下module之后才会生成
- return new AutoValue_User.GsonTypeAdapter(gson)
- .setDefaultAddr("默认地址"); //还可以设置默认值
- }
- }
3.2.2 编写TypeAdapterFactory
然后编写对应的编写TypeAdapterFactory类,使用@GsonTypeAdapterFactory
注解去修饰。
- @GsonTypeAdapterFactory
- public abstract class UserAdapterFactory implements TypeAdapterFactory {
- // 静态工厂方式
- public static TypeAdapterFactory create() {
- return new AutoValueGson_UserAdapterFactory();
- }
- }
3.2.3 Gson解析
上面搞好了之后,尝试来解析json为User看看。
- public class MainActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //json字符串
- String json = "{\"name\":\"天平\",\"addr\":\"广东\",\"age\":21,\"gender\":\"男\",\"hobby\":\"打代码\",\"sign\":\"签名\",\"date\":\"2017-3-13 14:36:19\"}";
- //初始化Gson
- Gson gson = new GsonBuilder()
- .registerTypeAdapterFactory(UserAdapterFactory.create()) //注册自定义的TypeAdapterFactory
- .setDateFormat("yyyy-MM-dd HH:mm:ss") //设置json里面的Date格式
- .create();
- //开始解析
- User user = gson.fromJson(json,User.class);
- //输出结果
- Log.e("@@", "onCreate: "+user.toString());
- }
- }
即可看到:
- onCreate: User{name=天平, addr=广东, age=21, gender=男, hobby=打代码, sign=签名, date=Mon Mar 13 14:36:19 GMT+08:00 2017}
四、小细节
4.1 Gson泛型支持
如果你的bean类里面有泛型,这时候你的TypeAdapter也需要泛型,还要添加参数TypeToken,例如:
- @AutoValue public abstract class Foo<A, B, C> {
- abstract A data();
- abstract List<B> dataList();
- abstract Map<String, List<C>> dataMap();
- public static <A, B, C> TypeAdapter<Foo<A, B, C>> typeAdapter(Gson gson,
- TypeToken<? extends Foo<A, B, C>> typeToken) {
- return new AutoValue_Foo.GsonTypeAdapter(gson, typeToken);
- }
- }
4.2 可选配置
添加了下面的设置,maps/collections将默认为它们的空类型(例如List - > Collections.emptyList()) 值为true或false。
- apt {
- arguments {
- autovaluegson.defaultCollectionsToEmpty 'true'
- }
- }
4.3 AutoValue plugin插件
可以生成create Builder等代码,不过不能生成TypeAdapter代码:
插件仓库搜索: AutoValue plugin
开源地址: https://github.com/afcastano/AutoValuePlugin
使用方法: 安装插件重启了As之后,在Bean里面Alt+回车 即可ADD
4.4 配合SqlDelight
AutoValue配合SqlDelight效果会更好噢。
五 setter方法变种实现
AutoValue修饰的类是都是immutable不变的,所以就没有了setter的方法。 我们应该怎么样补救呢?
方法1: 重新new
这种情况适用于 不是频繁的需要setter的话,重新new是个不错的方法。
例如还是上面的bean,添加了两个create方法,和Builder。第二个create方法就可以用来重新new,然后setter最新的数据进来:
- @AutoValue
- public abstract class User {
- abstract String name();
- abstract String addr();
- abstract int age();
- abstract String gender();
- abstract String hobby();
- abstract String sign();
- //创建方法
- public static User create(String name, String addr, int age, String gender, String hobby, String sign) {
- return builder()
- .name(name)
- .addr(addr)
- .age(age)
- .gender(gender)
- .hobby(hobby)
- .sign(sign)
- .build();
- }
- //setter的时候传递当前的user过来,这里重新builder,再设置
- public static Builder create(User user){
- return builder()
- .name(user.name())
- .addr(user.addr())
- .age(user.age())
- .gender(user.gender())
- .hobby(user.hobby())
- .sign(user.sign());
- }
- public static Builder builder() {
- return new AutoValue_User.Builder();
- }
- @AutoValue.Builder
- public abstract static class Builder {
- public abstract Builder name(String name);
- public abstract Builder addr(String addr);
- public abstract Builder age(int age);
- public abstract Builder gender(String gender);
- public abstract Builder hobby(String hobby);
- public abstract Builder sign(String sign);
- public abstract User build();
- }
- }
使用,例如我要更新签名:
- private void updateSign(User user){
- user = User.create(user).sign("新签名").build();
- }
方法2: 不要用AutoValue了
这种情况适用于你需要频繁的调用setter,如果用第一种方案的话,就需要频繁的new对象,对程序效率有大大的影响。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对w3xue的支持。如果你想了解更多相关内容请查看下面相关链接