Android AutoValue使用和扩展库

来源:互联网 发布:js兼容性注释 编辑:程序博客网 时间:2024/06/07 16:42

一、什么是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代码很多,到时候添加toStringhashCodeequals这些代码就更麻烦了(虽然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类:

@AutoValuepublic 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;  }}

这个类就是生成的类,里面就帮你编写好了各种方法hashCodetoStringequalsgettersetter等等。

2.3 构造方法

这时候构造方法利用自己写的一个方法来实现newAutoValue_User,在User类里面添加create方法进行调用生成的AutoValue_User,这时候bean的方法这样的:

@AutoValuepublic 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实现接口即可:

@AutoValuepublic 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类型:

@AutoValuepublic 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的就不能按照平常的方式来解析了,需要改变一下。

普及知识:

Gson的TypeAapter可以理解成自定义序列化和返序列化。通过实现JsonSerializer和JsonDeserializer进行序列化和反序列化,在Gson创建的时候registerTypeAdapter(你的自定义TypeAapter)。 具体请百度。

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是这样的:

@AutoValuepublic 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("默认地址");  //还可以设置默认值    }}

注意: TypeAdapter,这个TypeAdapter是Gson包里面的。AutoValue_User.GsonTypeAdapter(gson) 需要先make一下module之后才会生成。

3.2.2 编写TypeAdapterFactory

然后编写对应的编写TypeAdapterFactory类,使用@GsonTypeAdapterFactory注解去修饰。

@GsonTypeAdapterFactorypublic 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最新的数据进来:

@AutoValuepublic 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对象,对程序效率有大大的影响。

2 0