Extra Bindingライブラリの比較

  • 22
    Like
  • 0
    Comment
More than 1 year has passed since last update.

導入のモチベーション

Androidでは画面間のデータの受け渡しは、一般的には下のようにIntentにkey-valueを渡して行うと思います。

// FooActivity.java
public static final String KEY = "...";
public static final String KEY = "...";
public static final String KEY = "...";

private String stringValue;
private int intValue;
private boolean booleanValue;

public static void launch(...) {
    ...
    intent.putExtra(KEY, stringValue);
    intent.putExtra(KEY, intValue);
    intent.putExtra(KEY, booleanValue);
    ...
}

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    stringValue = getIntent().getStringExtra(KEY);
    intValue = getIntent().getIntExtra(KEY);
    booleanValue = getIntent().getBooleanExtra(KEY);
    ...
}

これが地味に面倒で、数年前にRoboGuiceを使っていたときは @InjectExtra というのがあり、Extraを自動的にbindできて便利だった(それがDIの範疇に含まれるかはさておき)記憶があるので、似たような機能を提供しているライブラリを探していました。

Extra Binding Libraries

ビルドツール コード生成方法 Extraの渡し方 シリアライズ Fragmentサポート
dart maven apt use generated class No Yes
IntentBuilder gradle apt use generated class No No
PrettyBundle gradle apt use generated class No Yes
AutoBundle gradle apt use generated class Yes Yes
injectextra gradle apt + bytecode weaving Intent#putExtra No No

好みの問題もあると思うのですが、私はこの中からコードの品質が良くて仕様を満たしている AutoBundle を選びました。いくつか選定したポイントを書きます。

ビルドツール

何か不都合があったときにPull Requestが送ることができるかは重要ですが、mavenはあまり触りたくなかったので必須ではないですがgradleを使っている方が都合が良かったです。

コード生成方法

どのライブラリもコード生成を行っているのですが、aptで実現できそうなコードでbytecode weavingをするのはメンテすることを考えるとちょっとやりすぎかなという気がします。

Extraの渡し方

Extraを渡される方のクラスはどのライブラリでも bind で値を代入するのですが、渡す側でもできればキーをどこかに書いたりしたくないので Intent#putExtra でなく自動生成して補完が効いたりすると嬉しいですね。たとえば以下のようなクラスだと

// FooActivity.java
public static final String KEY = "...";
public static final String KEY = "...";
public static final String KEY = "...";

private String stringValue;
private int intValue;
private boolean booleanValue;

public static void launch(...) {
    ...
    intent.putExtra(KEY, stringValue);
    intent.putExtra(KEY, intValue);
    intent.putExtra(KEY, booleanValue);
    ...
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    stringValue = getIntent().getStringExtra(KEY);
    intValue = getIntent().getIntExtra(KEY);
    booleanValue = getIntent().getBooleanExtra(KEY);
    ...
}

AutoBundleでは @AutoBundleField を付けることで #{class_name}AutoBundle クラスが生成されます。必須のパラメータはコンストラクタに、必須でないパラメータはビルダーのメソッドに渡すことができます。

// FooActivity.java
@AutoBundleField String stringValue;
@AutoBundleField int intValue;
@AutoBundleField(required = false) boolean booleanValue;

public static void launch(...) {
    ...
    FooActivityAutoBundle.createIntentBuilder(stringValue, intValue)
        .booleanValue(booleanValue)
        .build(context);
    ...
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    FooActivityAutoBundle.bind(this, getIntent());
    ...
}

シリアライズ

たとえばUserオブジェクトを渡すのに対応している型にシリアライズして、onCreateの中でデシリアライズしてとかだと面倒なので、自動で変換を行ってくれると嬉しいです。AutoBundleでは @AutoBundleField(converter = *.class) で変換を行うクラスを指定することができます。

@AutoBundleField(converter = UserConveter.class)

Fragmentサポート

Fragment用のbindingライブラリもありますが(sockeqwe/fragmentargs: Annotation Processor for setting arguments in android fragments)、できれば一つのライブラリでActivityとFragmentを統一的に扱えた方が学習コストが低くなって嬉しいです。

というわけで私はAutoBundleを使っています。