欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android AutoValue使用和扩展库

程序员文章站 2022-06-10 19:09:50
一、什么是autovalue 意思就是自动值,谷歌出品,添加@autovalue这样的注解 就能够自动生成代码,使得程序可能更短,更清晰。 支持java1.6+ git...

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

总结

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