热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

AndroidAutoValue使用和扩展库

今天小编就为大家分享一篇关于AndroidAutoValue使用和扩展库的文章,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

一、什么是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类:

@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地址: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 CREATOR = new Parcelable.Creator() {
  @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 {
  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地址: 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,这个TypeAdapter是Gson包里面的。
public static TypeAdapter 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 {
abstract A data();
abstract List dataList();
abstract Map> dataMap();
public static  TypeAdapter> typeAdapter(Gson gson,
TypeToken<&#63; extends Foo> 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对象,对程序效率有大大的影响。

总结

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


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
author-avatar
无语我去_296
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有