Parcelable 幫手
在 Android ,要將 object 由 Activities
或 services
之間傳送,必須將其放進 intent
中。除了 primitive types 外,object 必須 implement Parcelable
才能放在 intent
。Implement Parcelable
,不是難,而是麻煩,例如以下的 Foo
Class:
public class Foo {
private String myString;
private int myInt;
public Foo() {
}
}
變成 Parcelable
的話:
public class Foo implements Parcelable {
private String myString;
private int myInt;
public Foo() {
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.myString);
dest.writeInt(this.myInt);
}
protected Foo(Parcel in) {
this.myString = in.readString();
this.myInt = in.readInt();
}
public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>() {
@Override
public Foo createFromParcel(Parcel source) {
return new Foo(source);
}
@Override
public Foo[] newArray(int size) {
return new Foo[size];
}
};
}
多了兩個 methods、一個 constructor和一個 static variable。大部份都是 boilerplate code。當你有數十個 object 要這樣做的話,要寫這些真的令人覺得煩厭。若要加減 field,還要因應次序修改 writeToParcel()
和 constructor 。比起 getter & setter 更麻煩啊。
幸好,這些重覆性的 code 一定會有有心人寫程式方便人民!世界大同萬歳!
方法一:使用 Serializeable
你可以 implement Serializeable
,然後使用 intent.putExtra(String name, Serializable serializable)
。這是最簡單的做法,不需額外 coding 或 library。有時懶起來或想快速 proof of concept,我也會這樣做。
但是,這做法有一重大缺點,就是速度非常慢。有興趣的可參考別人的比較結果。總之,不建議在 production code 上這樣寫,別做壞手勢啊。
方法二:使用 Web - Parcelabler.com
可到 http://parcelabler.com/, 將 class 貼上去,能自動轉換為 Parcelable
。貼上的 class 不需完整,只需有 class 名和 field 名即足夠。
方法三:使用 Plugin - Android Parcelable Code Generator
若覺得使用 web 不夠快捷,也可使用 IntelliJ IDEA/Android Studio 的 plugin:
- 開啟 IntelliJ IDEA/Android Studio
- 到 Settings > Plugin
- 找尋 "Android Parcelable Code Generator"
- 安裝並重啟 IDE
安裝完成後,開啟想變成 Parcelable 的 file ,如 Foo.java
,點選 Menu > Code > Generate,選 "Parcelable" 便會自動生成對應的 methods,非常方便。
這個 plugin 的作者就是 parcelabler.com 的達人,有神快拜啊!
方法四:使用 library - AutoParcel
如果不想自己手動執行 plugin 的話,也可使用 AutoParcel
這 library,透過 android-apt 去自動生成支援 Parcelabe
的 class 。
要用此 library,必須在 gradle 的 dependencies
和 apply plugin
設定載入 android-apt:
buildscript {
repositories {
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
}
}
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
repositories {
mavenCentral()
jcenter()
maven {url "https://clojars.org/repo/"}
}
dependencies {
apt 'frankiesardo:auto-parcel:{{latest-version}}'
}
然後便可以將 class 寫成以下格式,加上 @AutoValue
:
@AutoValue
abstract class Person implements Parcelable {
abstract String name();
abstract List<Address> addresses();
abstract Map<Person, Integer> likes();
static Person create(String name, List<Address> addresses, Map<Person, Integer> likes) {
return new AutoValue_Person(name, addresses, likes);
}
}
之後便可直接使用該 object。就算之後有任何改動,也不需像使用 plugin 般要人手再 generate source code,android-apt 會自動幫你弄妥,更是直接方便。
結語
我自己是使用 plugin 去做的,下個 project 會試用 AutoParcel
,畢竟要自動的話,便要自動到底。
以前很怕寫 Parcelable
,有 plugin 後真是如淋春風,有多少寫多少。