当前位置: 移动技术网 > IT编程>移动开发>Android > Android AutoValue使用和扩展库

Android AutoValue使用和扩展库

2019年08月02日  | 移动技术网IT编程  | 我要评论

波多野结衣维基百科,dubike官网,netmeter

一、什么是autovalue

意思就是自动值,谷歌出品,添加@autovalue这样的注解 就能够自动生成代码,使得程序可能更短,更清晰。 支持java1.6+

github:

首先看一个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类:

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

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

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地址:

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

普及知识:

  • gson的typeaapter可以理解成自定义序列化和返序列化。通过实现jsonserializer和jsondeserializer进行序列化和反序列化,在gson创建的时候registertypeadapter(你的自定义typeaapter)。 具体请百度。

auto-value-gson 的github地址:

导包(当前最新是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("默认地址"); //还可以设置默认值
}
}

  • 注意: typeadapter,这个typeadapter是gson包里面的。autovalue_user.gsontypeadapter(gson) 需要先make一下module之后才会生成。

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

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对移动技术网的支持。如果你想了解更多相关内容请查看下面相关链接

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网