在 Android ,要將 object 由 Activitiesservices 之間傳送,必須將其放進 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

Parcelabler.com Screenshot

可到 http://parcelabler.com/, 將 class 貼上去,能自動轉換為 Parcelable。貼上的 class 不需完整,只需有 class 名和 field 名即足夠。

方法三:使用 Plugin - Android Parcelable Code Generator

若覺得使用 web 不夠快捷,也可使用 IntelliJ IDEA/Android Studio 的 plugin:

  1. 開啟 IntelliJ IDEA/Android Studio
  2. 到 Settings > Plugin
  3. 找尋 "Android Parcelable Code Generator"
  4. 安裝並重啟 IDE

安裝完成後,開啟想變成 Parcelable 的 file ,如 Foo.java,點選 Menu > Code > Generate,選 "Parcelable" 便會自動生成對應的 methods,非常方便。

這個 plugin 的作者就是 parcelabler.com 的達人,有神快拜啊!

方法四:使用 library - AutoParcel

如果不想自己手動執行 plugin 的話,也可使用 AutoParcel 這 library,透過 android-apt 去自動生成支援 Parcelabe 的 class 。

https://github.com/frankiesardo/auto-parcel

要用此 library,必須在 gradle 的 dependenciesapply 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 後真是如淋春風,有多少寫多少。

相關連結