Android Model正確使用姿勢(shì)——AutoValue

Android Model正確使用姿勢(shì)AutoValue

前言

簡介

簡單使用

ImmutableValue types

高級(jí)使用

Nullable

Gson序列化

Serializable Parcelable

Retrofit和Rxjava結(jié)合使用

相關(guān)插件

RoboPOJOGenerator

AutoValue plugin

原理介紹

AutoFactory

AutoService

AutoCommon

Auto相關(guān)使用

IntentBuilder

FragmentArgs

其他相關(guān)

Kotlin Data Class

Object-C

總結(jié)

參考連接

最近看到幾篇博客是關(guān)于AutoValue的,然后自己十分喜歡,一下子覺的這樣寫代碼很優(yōu)雅,所以決定自己也寫一篇文章介紹下AutoValue。

本文最先發(fā)表于Github,如有轉(zhuǎn)載,請(qǐng)注明轉(zhuǎn)載出處。

前言

首先說Android Model,在開發(fā)中網(wǎng)絡(luò)請(qǐng)求,以及數(shù)據(jù)庫操作等,我們都會(huì)定義一個(gè)Model,不同人對(duì)這個(gè)的說法不一樣,比如有Entry,Bean,Pojo。

然后開發(fā)的過程中會(huì)遇到下面問題:

構(gòu)成方法:自定義構(gòu)造方法,如果實(shí)體比較復(fù)雜,可能會(huì)用到工廠模式或者是建造者模式

序列化:比如實(shí)現(xiàn)Serializable接口,Parcelable接口。

Json解析:有時(shí)候直接使用的是json數(shù)據(jù),比如@SerializedName注解。

自定義方法:對(duì)Model的字段有setter,getter方法,toString的實(shí)現(xiàn),在處理hash的時(shí)候,需要實(shí)現(xiàn)equals和hashcode方法。

以上這么問題,其實(shí)在Eclipse和Android Studio中都是有快捷功能幫我們自動(dòng)生成,后面的代碼示例,就是我用Android Studio自動(dòng)生成的。

比如下面一個(gè)User類是我們的本次示例的一個(gè)Model,如果按照正常的寫法,是這樣的。


publicabstractclassUserimplementsSerializable{@SerializedName("id")privateintid;@SerializedName("name")privateString name;publicintgetId() {returnid;? ? }publicvoidsetId(intid) {this.id = id;? ? }publicStringgetName() {returnname;? ? }publicvoidsetName(String name) {this.name = name;? ? }@Overridepublicbooleanequals(Object o) {if(this== o)returntrue;if(o ==null|| getClass() != o.getClass())returnfalse;? ? ? ? User user = (User) o;if(id != user.id)returnfalse;returnname !=null? name.equals(user.name) : user.name ==null;? ? }@OverridepublicinthashCode() {intresult = id;? ? ? ? result =31* result + (name !=null? name.hashCode() :0);returnresult;? ? }@OverridepublicStringtoString() {return"User{"+"id="+ id +", name='"+ name +'\''+'}';? ? }}

簡介

官方文檔給出的解釋是這樣的,大致意思是說是一個(gè)生成Java不可變的值類型工具,仔細(xì)研讀源代碼后,使用的技術(shù)是Java Apt,這個(gè)后面再做詳細(xì)解釋。

AutoValue - Immutable value-type code generation for Java 1.6+.

簡單使用

按照上面的例子,如果是AutoValue,代碼是這樣的。

首先需要在Android項(xiàng)目里面引入apt功能,在項(xiàng)目根目錄的gradle中添加,

buildscript{

repositories {

jcenter()

}dependencies{? ? ? ? classpath'com.android.tools.build:gradle:2.2.2'// 引入apt插件? ? ? ? classpath'com.neenbedankt.gradle.plugins:android-apt:1.8'}}


其次在module(一般是app目錄)中g(shù)radle使用apt插件。

apply plugin:'com.android.application'apply plugin:'com.neenbedankt.android-apt'


最后加入AutoValue依賴。

dependencies{? ? provided'com.google.auto.value:auto-value:1.3'apt'com.google.auto.value:auto-value:1.3'}

修改User類,如下所示,User已經(jīng)變成了一個(gè)抽象類,類似于使用Retrofit一樣,申明已經(jīng)變成了一個(gè)接口,然后實(shí)現(xiàn)類是由AutoValue生成的代碼。

importcom.google.auto.value.AutoValue;@AutoValuepublicabstractclassUser{publicabstractintid();publicabstractStringname();publicstaticUsernewInstance(intid, String name) {returnnewAutoValue_User(id, name);? ? }}


我們可以看看AutoValue到底干了什么?

AutoValue會(huì)自動(dòng)生成一個(gè)AutoValue_User,這個(gè)類是繼承了上面申明的User類,這個(gè)是默認(rèn)default的訪問權(quán)限,那么在其他package中是無法訪問的,這樣在其他代碼里面也不會(huì)看到這么奇怪的名字。

同時(shí)所有的字段都是final類型,如果字段是對(duì)象類型的,那么還不能為空,這個(gè)問題先保留,后面再做詳解。因?yàn)樯昝鞯氖莊inal類型,那么所有的字段都是沒有setter方法的。

代碼里同時(shí)也實(shí)現(xiàn)了equals、hashcode、toString方法。

finalclass AutoValue_User extends User {privatefinalintid;privatefinalString name;? AutoValue_User(intid,? ? ? String name) {this.id = id;if(name ==null) {thrownewNullPointerException("Null name");? ? }this.name = name;? }@Overridepublicintid() {returnid;? }@OverridepublicStringname() {returnname;? }@OverridepublicStringtoString() {return"User{"+"id="+ id +", "+"name="+ name? ? ? ? +"}";? }@Overridepublicbooleanequals(Object o) {if(o ==this) {returntrue;? ? }if(oinstanceofUser) {? ? ? User that = (User) o;return(this.id == that.id())? ? ? ? ? && (this.name.equals(that.name()));? ? }returnfalse;? }@OverridepublicinthashCode() {inth =1;? ? h *=1000003;? ? h ^=this.id;? ? h *=1000003;? ? h ^=this.name.hashCode();returnh;? }}

Immutable/Value types

剛剛上面說到,所有的字段都是final類型,那么而且實(shí)現(xiàn)類也是final的,有個(gè)專業(yè)術(shù)語叫Immutable。

Immutable/Value types 這個(gè)概念對(duì)有些朋友來說可能還比較陌生,簡單來說就是一個(gè)數(shù)據(jù)對(duì)象一旦構(gòu)造完成,就再也無法修改了。

這樣有什么好處呢?最大的好處就是多線程訪問可以省去很多同步控制,因?yàn)樗鼈兪遣豢勺兊模坏?gòu)造完成,就不會(huì)存在多線程競(jìng)爭訪問問題了。多線程最麻煩的處理就是控制好讀寫問題,如果大家都是讀,那么就不存控制了,所以省去了很多同步操作。

更多關(guān)于Immutable 的介紹,可以參閱wiki

舉個(gè)Java中的例子:String和StringBuilder,String是immutable的,每次對(duì)于String對(duì)象的修改都將產(chǎn)生一個(gè)新的String對(duì)象,而原來的對(duì)象保持不變,而StringBuilder是mutable,因?yàn)槊看螌?duì)于它的對(duì)象的修改都作用于該對(duì)象本身,并沒有產(chǎn)生新的對(duì)象。

Immutable objects 比傳統(tǒng)的mutable對(duì)象在多線程應(yīng)用中更具有優(yōu)勢(shì),它不僅能夠保證對(duì)象的狀態(tài)不被改變,而且還可以不使用鎖機(jī)制就能被其他線程共享。

總結(jié)下Immutable對(duì)象的優(yōu)缺點(diǎn):

優(yōu)點(diǎn)

Immutable對(duì)象是線程安全的,可以不用被synchronize就在并發(fā)環(huán)境中共享

Immutable對(duì)象簡化了程序開發(fā),因?yàn)樗鼰o需使用額外的鎖機(jī)制就可以在線程間共享

Immutable對(duì)象提高了程序的性能,因?yàn)樗鼫p少了synchroinzed的使用

Immutable對(duì)象是可以被重復(fù)使用的,你可以將它們緩存起來重復(fù)使用,就像字符串字面量和整型數(shù)字一樣。你可以使用靜態(tài)工廠方法來提供類似于valueOf()這樣的方法,它可以從緩存中返回一個(gè)已經(jīng)存在的Immutable對(duì)象,而不是重新創(chuàng)建一個(gè)。

缺點(diǎn)

Immutable也有一個(gè)缺點(diǎn)就是會(huì)制造大量垃圾,由于他們不能被重用而且對(duì)于它們的使用就是”用“然后”扔“,字符串就是一個(gè)典型的例子,它會(huì)創(chuàng)造很多的垃圾,給垃圾收集帶來很大的麻煩。當(dāng)然這只是個(gè)極端的例子,合理的使用immutable對(duì)象會(huì)創(chuàng)造很大的價(jià)值。

高級(jí)使用

Nullable

上面說過如果類中有對(duì)象類型的成員變量,那么是為非空的,但是在實(shí)際情況下,有的字段的是值就是為null,所以在申明時(shí)候可申明為Nullable就可以了。

importandroid.support.annotation.Nullable;importcom.google.auto.value.AutoValue;importcom.google.gson.annotations.SerializedName;@AutoValuepublicabstractclassNullableUser{@SerializedName("id")publicabstractintid();@Nullable@SerializedName("name")publicabstractStringname();publicstaticNullableUsernewInstance(intid, String name) {returnnewAutoValue_NullableUser(id, name);? ? }}

生成代碼:

finalclass AutoValue_NullableUser extends NullableUser {privatefinalintid;privatefinalString name;? AutoValue_NullableUser(intid,@NullableString name) {this.id = id;this.name = name;? }}

測(cè)試用例

@Test(expected = NullPointerException.class)publicvoidtestUserNullPointException()throwsException {? ? ? ? User.newInstance(100,null);? ? }@TestpublicvoidtestUserNullable() {? ? ? ? NullableUser user = NullableUser.newInstance(100,"test");? ? ? ? System.out.println("user = "+ user);? ? ? ? Assert.assertEquals(user.id(),100);? ? ? ? Assert.assertEquals(user.name(),"test");? ? }

Gson序列化

Gson 使用比較麻煩,在普通的Model中,只需要在字段上面添加 @SerializedName注解即可。但是使用AutoValue,稍微有點(diǎn)繁瑣。

首先需要引入一個(gè)依賴包,這里是Auto value gson Github

provided'com.ryanharter.auto.value:auto-value-gson:0.4.4'apt'com.ryanharter.auto.value:auto-value-gson:0.4.4'

其次申明的抽象類中,每個(gè)方法上面添加對(duì)應(yīng)的注解,然后再添加一個(gè)typeAdapter方法,申明這個(gè)方法,Gson就會(huì)根據(jù)這個(gè)找到對(duì)應(yīng)的adapter,如下所示。

@AutoValuepublicabstractclassUser{@SerializedName("id")publicabstractintid();@SerializedName("name")publicabstractStringname();publicstaticUsernewInstance(intid, String name) {returnnewAutoValue_User(id, name);? ? }publicstaticTypeAdaptertypeAdapter(Gson gson) {returnnewAutoValue_User.GsonTypeAdapter(gson);? ? }}


typeAdapter方法模板如下,T就是你當(dāng)前Model的名字,寫完以后會(huì)出現(xiàn)錯(cuò)誤,沒事重新編譯下就好了,這樣就會(huì)重新生成了代碼。

publicstaticTypeAdaptertypeAdapter(Gson gson) {returnnewAutoValue_T.GsonTypeAdapter(gson);}


第三申明一個(gè)TypeAdapterFactory的一個(gè)實(shí)現(xiàn)類,這個(gè)類是abstract的,AutoValue也會(huì)自動(dòng)生成其實(shí)現(xiàn)類。

@GsonTypeAdapterFactorypublicabstractclassMyAdapterFactoryimplementsTypeAdapterFactory{publicstaticTypeAdapterFactorycreate() {returnnewAutoValueGson_MyAdapterFactory();? ? }}


最后是單元測(cè)試,在json字符串轉(zhuǎn)Model的時(shí)候,會(huì)使用一個(gè)Gson對(duì)象,這個(gè)對(duì)象不是平常使用的對(duì)象,需要自定義配置一些東西,然后這里就用到了上面所申明的MyAdapterFactory。

@TestpublicvoidtestUserToJson() {? ? ? ? User user = User.newInstance(100,"test");? ? ? ? String json =newGson().toJson(user);? ? ? ? System.out.println(json);? ? ? ? Assert.assertEquals("{\"id\":100,\"name\":\"test\"}", json);? ? }@TestpublicvoidtestUserParseFromJson() {? ? ? ? String json ="{\"id\":100,\"name\":\"test\"}";// 自定義的Gson對(duì)象,需要配置 MyAdapterFactoryGson gson =newGsonBuilder().registerTypeAdapterFactory(MyAdapterFactory.create()).create();? ? ? ? User user = gson.fromJson(json, User.class);? ? ? ? System.out.println(user);? ? ? ? Assert.assertNotNull(user);? ? ? ? Assert.assertEquals(user.name(),"test");? ? ? ? Assert.assertEquals(user.id(),100);? ? ? ? NullableUser nullableUser = gson.fromJson(json, NullableUser.class);? ? ? ? System.out.println(nullableUser);? ? ? ? Assert.assertNotNull(nullableUser);? ? ? ? Assert.assertEquals(nullableUser.name(),"test");? ? ? ? Assert.assertEquals(nullableUser.id(),100);? ? }


Serializable & Parcelable

Serializable是Java自帶的序列化方式,和AutoValue結(jié)合不影響原先使用,只需要在申明的Model中實(shí)現(xiàn)Serializable接口即可。

Parcelable是Android提供的序列化方式,如果需要和AutoValue結(jié)合使用,和Serializable基本差不多,實(shí)現(xiàn)相關(guān)接口,然后在Gradle文件引入相關(guān)apt依賴即可。

apt'com.ryanharter.auto.value:auto-value-parcel:0.2.5'// OptionallyforTypeAdapter support? ? // compile'com.ryanharter.auto.value:auto-value-parcel-adapter:0.2.5'


auto-value-parcel Github地址

上面的auto-value-parcel-adapter是可選項(xiàng),是auto-value-parcel提供自定義類型轉(zhuǎn)化,相關(guān)使用可以參見Github地址。

檢查下Autovalue自動(dòng)給我們實(shí)現(xiàn)的代碼,果然不出所料,全部自動(dòng)生成了。

finalclass AutoValue_User extends $AutoValue_User {publicstaticfinalParcelable.Creator CREATOR =newParcelable.Creator() {@OverridepublicAutoValue_UsercreateFromParcel(Parcel in) {returnnewAutoValue_User(? ? ? ? ? in.readInt(),? ? ? ? ? in.readString()? ? ? );? ? }@OverridepublicAutoValue_User[]newArray(intsize) {returnnewAutoValue_User[size];? ? }? };? AutoValue_User(intid, String name) {super(id, name);? }@OverridepublicvoidwriteToParcel(Parcel dest,intflags) {? ? dest.writeInt(id());? ? dest.writeString(name());? }@OverridepublicintdescribeContents() {return0;? }}


Retrofit和Rxjava結(jié)合使用

Android 開發(fā)的時(shí)候,很多開發(fā)者使用Retrofit這個(gè)網(wǎng)絡(luò)庫,以及RxJava異步工具。下面舉例如何結(jié)合使用AutoValue,Retrofit,Rxjava。

這里有個(gè)獲取天氣的接口,返回的結(jié)果是json,我們用這個(gè)來測(cè)試下Retrofit。

// https://api.thinkpage.cn/v3/weather/now.json?key=x4qjfuniyu97mt9y&location=beijing&language=zh-Hans&unit=c{"results": [? ? {"location": {"id":"WX4FBXXFKE4F","name":"北京","country":"CN","path":"北京,北京,中國","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now": {"text":"霾","code":"31","temperature":"10"},"last_update":"2016-12-02T14:45:00+08:00"}? ]}


申明Retrofit Api接口,一個(gè)普通的調(diào)用,一個(gè)是RxJava的方式。

publicinterfaceIWeatherApi{@GET("/v3/weather/now.json?key=x4qjfuniyu97mt9y&location=beijing&language=zh-Hans&unit=c")? ? Call getWeather();@GET("/v3/weather/now.json?key=x4qjfuniyu97mt9y&location=beijing&language=zh-Hans&unit=c")? ? Observable getWeatherWithRx();}


Retrofit 接口創(chuàng)建

publicclassRetrofitUtil{publicstatic TcreateApi(@NonNull Class tClass, Gson gson) {returnnewRetrofit.Builder()? ? ? ? ? ? ? ? .baseUrl("https://api.thinkpage.cn")? ? ? ? ? ? ? ? .client(newOkHttpClient.Builder().build())? ? ? ? ? ? ? ? .addConverterFactory(GsonConverterFactory.create(gson))? ? ? ? ? ? ? ? .addCallAdapterFactory(RxJavaCallAdapterFactory.create())? ? ? ? ? ? ? ? .build()? ? ? ? ? ? ? ? .create(tClass);? ? }}


Weather Model申明

publicabstractclassWeather{@SerializedName("results")publicabstractListresults();publicstaticTypeAdaptertypeAdapter(Gson gson) {returnnewAutoValue_Weather.GsonTypeAdapter(gson);? ? }}


測(cè)試用例,注意:Retrofit使用Gson和前面使用Gson使用方式一樣,需要自己自定義,不然無法解決json解析問題。

@TestpublicvoidtestRetrofitWithAutoValue() {? ? ? ? Gson gson =newGsonBuilder().registerTypeAdapterFactory(MyAdapterFactory.create()).create();? ? ? ? IWeatherApi weatherApi = RetrofitUtil.createApi(IWeatherApi.class, gson);try{// 同步調(diào)用Weather weather = weatherApi.getWeather().execute().body();? ? ? ? ? ? Assert.assertNotNull(weather);? ? ? ? ? ? System.out.println(weather);// Rxjava 使用weatherApi.getWeatherWithRx().subscribe(newAction1() {@Overridepublicvoidcall(Weather weather) {? ? ? ? ? ? ? ? ? ? System.out.println(weather);? ? ? ? ? ? ? ? }? ? ? ? ? ? });? ? ? ? }catch(IOException e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? }? ? }

運(yùn)行結(jié)果,正常的返回天氣信息。

Weather{results=[ResultsItem{now=Now{code=31, temperature=9,text=霾}, lastUpdate=2016-12-02T14:15:00+08:00, location=Location{country=CN, path=北京,北京,中國, timezone=Asia/Shanghai, timezoneOffset=+08:00,name=北京,id=WX4FBXXFKE4F}}]}Weather{results=[ResultsItem{now=Now{code=31, temperature=9,text=霾}, lastUpdate=2016-12-02T14:15:00+08:00, location=Location{country=CN, path=北京,北京,中國, timezone=Asia/Shanghai, timezoneOffset=+08:00,name=北京,id=WX4FBXXFKE4F}}]}


相關(guān)插件

RoboPOJOGenerator

GsonFormat是一款A(yù)ndroid Studio的插件,它可以把json字符串,轉(zhuǎn)變成Model對(duì)象,很多人都喜歡用它。

但是如果使用了AutoValue,那么原先的插件就不能使用了,沒有關(guān)系,本來打算自己高仿GsonFormat重新寫了一個(gè)插件,以實(shí)現(xiàn)我們的需求,后面又發(fā)現(xiàn)有一款插件可以實(shí)現(xiàn)——RoboPOJOGenerator。

RoboPOJOGenerator使用,RoboPOJOGenerator Github地址

AutoValue plugin

上面我們發(fā)現(xiàn)有了json字符串,有時(shí)候還要寫factory和buildder方法,那么問題來了,沒有插件能幫我們實(shí)現(xiàn)這個(gè)步驟,然代碼更加的優(yōu)雅,開發(fā)更加高效?

答案是肯定的,Autovalue plugin就是干這個(gè)事的。

Auto value plugin Github

我們用剛剛上面的Weather做演示,相關(guān)演示:

原理介紹

本文重點(diǎn)介紹的AutoValue只是Google Auto中的一小部分,Auto中還有其他好玩的。

AutoFactory

AutoFactory和AutoValue類似,可以自動(dòng)幫助代碼生成工廠類,兼容Java 依賴注入標(biāo)準(zhǔn)(JSR-330)。

代碼示例

@AutoFactorypublicclassFactoryUser{privatefinalintid;privatefinalString name;publicFactoryUser(intid, String name) {this.id = id;this.name = name;? ? }publicintgetId() {returnid;? ? }publicStringgetName() {returnname;? ? }@OverridepublicStringtoString() {return"FactoryUser{"+"id="+ id +", name='"+ name +'\''+'}';? ? }}

生成后的代碼

publicfinalclassFactoryUserFactory{@InjectpublicFactoryUserFactory() {? }publicFactoryUsercreate(intid, String name) {returnnewFactoryUser(id, name);? }}

測(cè)試代碼

@TestpublicvoidtestFactoryUser() {? ? ? ? FactoryUser user =newFactoryUserFactory().create(100,"test");? ? ? ? System.out.println(user);? ? ? ? Assert.assertNotNull(user);? ? ? ? Assert.assertEquals(100, user.getId());? ? ? ? Assert.assertEquals("test", user.getName());? ? }

AutoService

AutoService比較簡單,就是在使用Java APT的時(shí)候,使用AutoService注解,可以自動(dòng)生成meta信息。

AutoCommon

這個(gè)是Google對(duì)Java Apt的一個(gè)擴(kuò)展,一般的在自己寫Apt的時(shí)候,都需要繼承AbstractProcessor,但是google對(duì)它進(jìn)行了擴(kuò)展,BasicAnnotationProcessor,如果你想自己寫個(gè)工具,那么就可以使用這個(gè)了。

給大家舉個(gè)栗子,Dagger當(dāng)初是Square公司受到Guice的啟發(fā),然后自己開發(fā)出一套依賴注入框架,當(dāng)時(shí)Dagger使用的是Java反射,大家知道Java反射的效率其實(shí)并不高。

再后來都到了AutoValue的啟發(fā),在Dagger的分支上切個(gè)新分支,開發(fā)出Dagger2,然后這個(gè)Dagger2是由Google維護(hù)的,我們可以在Dagger2的Github上面找到證據(jù)。

Auto相關(guān)使用

IntentBuilder

有時(shí)候幾個(gè)Activity之間相互跳轉(zhuǎn)的時(shí)候需要傳遞一些參數(shù),這些參數(shù)可以是基本類型,也有可能是復(fù)雜的類型,如果是負(fù)責(zé)的類型,必須要實(shí)現(xiàn)Serializable 或 Parcelable接口,上面也有介紹。

下面推IntentBuilder,IntentBuilder也是利用代碼生成的方法實(shí)現(xiàn)的。

IntentBuilder Github

Activity傳參

@IntentBuilderclass DetailActivity extends Activity {@ExtraString id;@Extra@NullableString title;@OverridepublicvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);? ? ? ? DetailActivityIntentBuilder.inject(getIntent(),this);// TODO use id and title}}// 調(diào)用方式startActivity(newDetailActivityIntentBuilder("12345")? ? ? ? .title("MyTitle")? ? ? ? .build(context))

Service傳參

@IntentBuilderclass DownloadService extends IntentService {@ExtraString downloadUrl;@OverrideprotectedvoidonHandleIntent(Intent intent) {? ? ? ? MyServiceIntentBuilder.inject(intent,this);? ? }}startService(newDownloadServiceIntentBuilder("http://google.com").build(context))

FragmentArgs

上面介紹了Activity、Service的傳參,但Fragment的傳參方式是不一樣的,還有需要提醒一句一般通過setter方法給Fragment傳參是不是正確的方式,必須通過setArgs的方式。

fragmentargs Github

相關(guān)代碼示例:

@FragmentWithArgspublicclassMyFragmentextendsFragment{@Argintid;@OverridepublicvoidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);? ? ? ? FragmentArgs.inject(this);// inject 之后,就可以使用 id 了}}MyFragment fragment = MyFragmentBuilder.newMyFragment(101);

其他相關(guān)

Kotlin Data Class

Kotlin 是一個(gè)基于 JVM 的新的編程語言,由 JetBrains 開發(fā)。有機(jī)會(huì)可以向大家介紹這種語言。

Kotlin 中提供一種類似于AutoValue中的功能,Data Class表示這個(gè)類似是一個(gè)數(shù)據(jù)類型。

比如下面是kotlin中對(duì)Model的寫法,就是這么的簡單、明了、優(yōu)雅。

dataclassKotlinUser(valid:Int,valname:String)

Kotlin與Java是可以相互調(diào)用的。下面是Java的測(cè)試用例。

publicclassUserTest{@TestpublicvoidtestUser() {? ? ? ? KotlinUser user =newKotlinUser(100,"test");? ? ? ? System.out.println(user);? ? ? ? Assert.assertEquals(100, user.getId());? ? ? ? Assert.assertEquals("test", user.getName());? ? }}

我們可以反編譯Kotlin生成的class字節(jié)碼,看看這個(gè)中間到底發(fā)生了什么,很明顯Kotlin做了很多的語法糖,這里編譯器生成的代碼和上面Autovalue生成的代碼很像。

Object-C

Object-C中可以過直接申明@property方式,然后就可以自動(dòng)實(shí)現(xiàn)setter和getter方法,如果要實(shí)現(xiàn)Immutable type方式,需要注明readonly。

hash、equals、description如果使用APPCode,代碼是可以自動(dòng)生成的。

@interfaceOcUser:NSObject@property(readonly)intid;@property(retain,readonly)NSString*name;- (instancetype)initWithId:(int)idname:(NSString*)name;- (NSString*)description;- (BOOL)isEqual:(id)other;- (BOOL)isEqualToUser:(OcUser *)user;- (NSUInteger)hash;@end// ==========================#import"OcUser.h"@implementationOcUser{}- (instancetype)initWithId:(int)idname:(NSString*)name {self= [superinit];if(self) {? ? ? ? _id=id;? ? ? ? _name = name;? ? }returnself;}- (BOOL)isEqual:(id)other {if(other ==self)returnYES;if(!other || ![[other class] isEqual:[selfclass]])returnNO;return[selfisEqualToUser:other];}- (BOOL)isEqualToUser:(OcUser *)user {if(self== user)returnYES;if(user ==nil)returnNO;if(self.id!= user.id)returnNO;return!(self.name!= user.name&& ![self.nameisEqualToString:user.name]);}- (NSUInteger)hash {? ? NSUInteger hash = (NSUInteger)self.id;? ? hash = hash *31u + [self.namehash];returnhash;}- (NSString*)description {NSMutableString*description = [NSMutableStringstringWithFormat:@"<%@: ", NSStringFromClass([selfclass])];? ? [description appendFormat:@"self.id=%i",self.id];? ? [description appendFormat:@", self.name=%@",self.name];? ? [description appendString:@">"];returndescription;}@end

測(cè)試用例

#import#import"OcUser.h"intmain(intargc,constchar*argv[]) {? ? @autoreleasepool {? ? ? ? OcUser *user = [[OcUser alloc] initWithId:100name:@"test"];NSLog(@"user = %@", user);? ? }return0;}// 運(yùn)行結(jié)果// user =

總結(jié)

本文主要介紹了Autovalue的主要用法,以及AutoValu周邊只是,可能說的比較多,比較雜,而且有的地方也不夠深入,但是個(gè)人覺的這是一種思路,一種解決方案,后面如果自己需要造輪子的時(shí)候,我們是可以借鑒的。

本示例代碼地址AutoValueDemo

參考連接

AutoValueDemo

完美Model之AutoValue使用

完美的安卓 model 層架構(gòu)(上)

完美的安卓 model 層架構(gòu)(下)

AutoValue Github

Java Immutable 介紹

Auto value gson Github

Auto value parcel Github

RoboPOJOGenerator Github

Auto value plugin Github

IntentBuilder Github

Fragmentargs Github

版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,055評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,346評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,889評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,118評(píng)論 0 286
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,637評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,558評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,739評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,980評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評(píng)論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,347評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,702評(píng)論 2 370

推薦閱讀更多精彩內(nèi)容