Android Model正確使用姿勢——AutoValue

Android Model正確使用姿勢AutoValue

前言

簡介

簡單使用

ImmutableValue types

高級使用

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)載告嘲,請注明轉(zhuǎn)載出處。

前言

首先說Android Model奖地,在開發(fā)中網(wǎng)絡(luò)請求橄唬,以及數(shù)據(jù)庫操作等,我們都會定義一個Model参歹,不同人對這個的說法不一樣仰楚,比如有Entry,Bean犬庇,Pojo僧界。

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

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

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

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

自定義方法:對Model的字段有setter涨共,getter方法,toString的實現(xiàn)闯狱,在處理hash的時候煞赢,需要實現(xiàn)equals和hashcode方法。

以上這么問題哄孤,其實在Eclipse和Android Studio中都是有快捷功能幫我們自動生成照筑,后面的代碼示例,就是我用Android Studio自動生成的瘦陈。

比如下面一個User類是我們的本次示例的一個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 +'\''+'}';? ? }}

簡介

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

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

簡單使用

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

首先需要在Android項目里面引入apt功能醒陆,在項目根目錄的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)變成了一個抽象類澡刹,類似于使用Retrofit一樣呻征,申明已經(jīng)變成了一個接口,然后實現(xiàn)類是由AutoValue生成的代碼罢浇。

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


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

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

同時所有的字段都是final類型阵子,如果字段是對象類型的,那么還不能為空胜蛉,這個問題先保留挠进,后面再做詳解色乾。因為申明的是final類型,那么所有的字段都是沒有setter方法的领突。

代碼里同時也實現(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類型,那么而且實現(xiàn)類也是final的金砍,有個專業(yè)術(shù)語叫Immutable局蚀。

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

這樣有什么好處呢?最大的好處就是多線程訪問可以省去很多同步控制鹅巍,因為它們是不可變的千扶,一旦構(gòu)造完成,就不會存在多線程競爭訪問問題了骆捧。多線程最麻煩的處理就是控制好讀寫問題澎羞,如果大家都是讀,那么就不存控制了凑懂,所以省去了很多同步操作。

更多關(guān)于Immutable 的介紹梧宫,可以參閱wiki接谨。

舉個Java中的例子:String和StringBuilder,String是immutable的塘匣,每次對于String對象的修改都將產(chǎn)生一個新的String對象脓豪,而原來的對象保持不變,而StringBuilder是mutable忌卤,因為每次對于它的對象的修改都作用于該對象本身扫夜,并沒有產(chǎn)生新的對象。

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

總結(jié)下Immutable對象的優(yōu)缺點:

優(yōu)點

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

Immutable對象簡化了程序開發(fā)颗味,因為它無需使用額外的鎖機(jī)制就可以在線程間共享

Immutable對象提高了程序的性能,因為它減少了synchroinzed的使用

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

缺點

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

高級使用

Nullable

上面說過如果類中有對象類型的成員變量圆丹,那么是為非空的滩愁,但是在實際情況下,有的字段的是值就是為null辫封,所以在申明時候可申明為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;? }}

測試用例

@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,稍微有點繁瑣欣福。

首先需要引入一個依賴包责球,這里是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'

其次申明的抽象類中拓劝,每個方法上面添加對應(yīng)的注解雏逾,然后再添加一個typeAdapter方法,申明這個方法郑临,Gson就會根據(jù)這個找到對應(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的名字,寫完以后會出現(xiàn)錯誤笨触,沒事重新編譯下就好了说榆,這樣就會重新生成了代碼唱蒸。

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


第三申明一個TypeAdapterFactory的一個實現(xiàn)類屁魏,這個類是abstract的,AutoValue也會自動生成其實現(xiàn)類。

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


最后是單元測試宪摧,在json字符串轉(zhuǎn)Model的時候沿彭,會使用一個Gson對象睦裳,這個對象不是平常使用的對象糙箍,需要自定義配置一些東西,然后這里就用到了上面所申明的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對象饰剥,需要配置 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中實現(xiàn)Serializable接口即可。

Parcelable是Android提供的序列化方式测秸,如果需要和AutoValue結(jié)合使用,和Serializable基本差不多吧碾,實現(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是可選項呢堰,是auto-value-parcel提供自定義類型轉(zhuǎn)化,相關(guān)使用可以參見Github地址凡泣。

檢查下Autovalue自動給我們實現(xiàn)的代碼枉疼,果然不出所料,全部自動生成了鞋拟。

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ā)的時候骂维,很多開發(fā)者使用Retrofit這個網(wǎng)絡(luò)庫,以及RxJava異步工具贺纲。下面舉例如何結(jié)合使用AutoValue航闺,Retrofit,Rxjava猴誊。

這里有個獲取天氣的接口潦刃,返回的結(jié)果是json,我們用這個來測試下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接口福铅,一個普通的調(diào)用萝毛,一個是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);? ? }}


測試用例,注意: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();? ? ? ? }? ? }

運行結(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對象通今,很多人都喜歡用它粥谬。

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

RoboPOJOGenerator使用,RoboPOJOGenerator Github地址

AutoValue plugin

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

答案是肯定的屡拨,Autovalue plugin就是干這個事的谦絮。

Auto value plugin Github

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

原理介紹

本文重點介紹的AutoValue只是Google Auto中的一小部分洁仗,Auto中還有其他好玩的层皱。

AutoFactory

AutoFactory和AutoValue類似,可以自動幫助代碼生成工廠類赠潦,兼容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);? }}

測試代碼

@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的時候她奥,使用AutoService注解瓮增,可以自動生成meta信息。

AutoCommon

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

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

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

Auto相關(guān)使用

IntentBuilder

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

下面推IntentBuilder腊状,IntentBuilder也是利用代碼生成的方法實現(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 是一個基于 JVM 的新的編程語言同蜻,由 JetBrains 開發(fā)棚点。有機(jī)會可以向大家介紹這種語言。

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

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

dataclassKotlinUser(valid:Int,valname:String)

Kotlin與Java是可以相互調(diào)用的桃序。下面是Java的測試用例杖虾。

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

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

Object-C

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

hash间影、equals、description如果使用APPCode茄茁,代碼是可以自動生成的魂贬。

@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

測試用例

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

總結(jié)

本文主要介紹了Autovalue的主要用法,以及AutoValu周邊只是裙顽,可能說的比較多付燥,比較雜,而且有的地方也不夠深入愈犹,但是個人覺的這是一種思路键科,一種解決方案,后面如果自己需要造輪子的時候漩怎,我們是可以借鑒的勋颖。

本示例代碼地址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)容合作請聯(lián)系作者
  • 序言:七十年代末饭玲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子叁执,更是在濱河造成了極大的恐慌茄厘,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谈宛,死亡現(xiàn)場離奇詭異次哈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)吆录,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門亿乳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人径筏,你說我怎么就攤上這事葛假。” “怎么了滋恬?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵聊训,是天一觀的道長。 經(jīng)常有香客問我恢氯,道長带斑,這世上最難降的妖魔是什么鼓寺? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮勋磕,結(jié)果婚禮上妈候,老公的妹妹穿的比我還像新娘。我一直安慰自己挂滓,他們只是感情好苦银,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赶站,像睡著了一般幔虏。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贝椿,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天想括,我揣著相機(jī)與錄音,去河邊找鬼烙博。 笑死瑟蜈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的渣窜。 我是一名探鬼主播踪栋,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼图毕!你這毒婦竟也來了夷都?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤予颤,失蹤者是張志新(化名)和其女友劉穎囤官,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛤虐,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡党饮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了驳庭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刑顺。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖饲常,靈堂內(nèi)的尸體忽然破棺而出蹲堂,到底是詐尸還是另有隱情,我是刑警寧澤贝淤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布柒竞,位于F島的核電站,受9級特大地震影響播聪,放射性物質(zhì)發(fā)生泄漏朽基。R本人自食惡果不足惜布隔,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望稼虎。 院中可真熱鬧衅檀,春花似錦、人聲如沸霎俩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茸苇。三九已至排苍,卻和暖如春沦寂,著一層夾襖步出監(jiān)牢的瞬間学密,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工传藏, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留腻暮,地道東北人。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓毯侦,卻偏偏與公主長得像哭靖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子侈离,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

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