Speee DEVELOPER BLOG

Speee開発陣による技術情報発信ブログです。 メディア開発・運用、スマートフォンアプリ開発、Webマーケティング、アドテクなどで培った技術ノウハウを発信していきます!

Androidアプリのソースコードを美しくするライブラリ2選

ご紹介

こんにちは。何でも屋さんです。

暑くなってきました。そしてそれ以上にW杯で熱いです。みんな応援するチームが勝つことを願いながら選手たちのスーパプレイで盛り上がっている中、Android開発も色々熱くなって来ました。

概要

最近のAndroidではscaloidを始めGroovy on Androidgoandroidまで、いろんな開発手法が出てきて盛り上がっています。期待のAndroid StudioはGradleを採用しており、現在ではかなり安定してきましたので、少し前のAndroid開発環境と比べて飛躍的によくなりました。
また、開発環境だけでなく、ライブラリを使って、より簡単に読みやすいコードを書くサポートをすることもできます。このようなオープンソースのライブラリもかなり充実してきており、Android開発に欠かせない技術になってきました。そこで今回は、知らないと損する実用ライブラリを二つ紹介致します。

Guava

ウェブ開発でなじみのApache Commonsに替わる機能を提供しているGoogleOSSコアライブラリです。Apache Commonsと比較してモダンな実装が可能になります。例えば互換性中心のApache Commonsではジェネリクス関連機能がしっかりしていないですが、GuavaではCollectionsパッケージでそれらが全て利用できます。ちょうどAndroid開発ではJava 1.6を中心に行うためGuavaはうってつけになります。
Guavaはコアライブラリですので多数の便利なパッケージで構成されていますが今回は一部の機能だけご紹介致します。
リスト生成時に両方同じ型を指定するなど不便だった書き方が短くなりました。ここはJava 1.7でもダイアモンド演算子を使って短く出来ますがnew嫌いとしてはguavaの方が好みです。

// 既存
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

// guava
List<Map<String, Object>> list = Lists.newArrayList();

// 参考:Java 1.7
List<Map<String, Object>> list = new ArrayList<>();

[/java]
<span style="color: #000000">また配列の初期化も簡単に書けるようになります。guavaを使わなくても可能ではありますが非効率的なコードになります。</span>
[java]

// 既存
List<String> stringList = new ArrayList<String>();
stringList.add("しお");
stringList.add("ごま");
stringList.add("よぼ");

// guava
List<String> stringList = Lists.newArrayList("しお", "ごま", "よぼ");

// 参考:guava無しだと
List<String> stringList = new ArrayList<String>(Arrays.asList("しお", "ごま", "よぼ"));

これらの使い方はMapやSetでもそのまま使えます。

// Maps
Map<String, Boolean> map = Maps.newHashMap();

// Sets
Set<String> set = Sets.newHashSet("しお", "ごま", "よぼ");

// ListsとImmutableMapの組み合わせ
List<Map<String, Object>> myCats = Lists.newArrayList(ImmutableMap.<String, Object>of("うすい", "しお", "こい", "ごま"));

文字列操作関連でも便利な機能を提供しています。

// isEmpty系
Strings.isNullOrEmpty(StringObj)

// split系とcollectの組み合わせ
String cardNumber = "3451-1231 8136-4123";
CharMatcher charMatcher = CharMatcher.WHITESPACE.or(CharMatcher.is('-'));
Iterable<String> numberGroups = Splitter.on(matcher).split(cardNumber);
List<String> numberGroupList = Lists.newArrayList(numberGroups);
// ※Splitter.splitToListもありますが、投稿時のバージョン(18)ではまだBetaであるためsplitを紹介しています。

// MapからStringのjoin
Map<String, String> myCats = ImmutableMap.<String, String>of("name", "しお", "status", null);
MapJoiner mapJoiner = Joiner.on("&").withKeyValueSeparator("=").useForNull("休み");
mapJoiner.join(myCats);  // name=しお&status=休み

そして紹介した機能以外にもI/Oに関連する様々な機能やプリミティブ型向けの便利なユーティリティ等があります。ぜひguava wikiを参考して短く賢いコードを書き上げましょう。

Android Annotations

Javaアノテーションを120%活用した本当に便利なライブラリです。メンバー変数やメソッドに対してアノテーションを宣言することだけでAndroid特有の冗長化したコードから脱出できます。サンプルコードだけでもAndroid Annotationsの強力さがすぐ分かるはずです。 最近ではActivity中心の構成よりはFragment構成が多くなっているため今回はFragmentを例にしますが基本的な使い方や機能はActivityも同じです。 下記は一般的なfragmentのコードです。

public class MyCatsDetailFragment extends Fragment {     
    // fragmentのパラメータ
    private HashMap<String, Object> nekoObj;
    // fragmentのview
    private TextView nameLabel;
    // fragmentのview2
    private ImageView iconView;    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // fragmentのパラメータ取得
        nekoObj = (HashMap<String, Object>)args.getSerializable("nekoObj");
        // レイアウトセット
        View view = inflater.inflate(R.layout.neko_detail, null);
        // Viewの初期化
        nameLabel = (TextView)view.findViewById(R.id.label_neko_detail);
        nameLabel.setText(nekoObj.get("name").toString());
        iconView = (ImageView)view.findViewById(R.id.icon_neko_detail);
        iconView.setImageBitmap((Bitmap)nekoObj.get("icon"));
        // イベント設定
        view.findViewById(R.id.btn_back_to_list).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d("log", "リスト画面に戻ります");
            }
        });
        return view;
    }
}

そして上記のコードにAndroid Annotationを適用したものが下記です。

@EFragment(R.layout.sub_menu)
public class MyCatsDetailFragment extends Fragment {
    @FragmentArg
    HashMap<String, Object> nekoObj;
    @ViewById(R.id.label_neko_detail)
    TextView nameLabel;
    @ViewById(R.id.icon_neko_detail)
    ImageView iconView;    
    @AfterViews
    void initViews() {
        nameLabel.setText(nekoObj.get("name").toString());
        iconView.setImageBitmap((Bitmap)nekoObj.get("icon"));
    }
    @Click(R.id.btn_back_to_list)
    void backToList(View view) {
        Log.d("log", "リスト画面に戻ります");
    }
}

ほんの一部のアノテーションだけでもかなり短くなりましたし読み易くなりました。

少し解説をすると@EFragmentを宣言することでAndroid Annotationsを適用することになります。またレイアウトidを設定することで面倒だったonCreateViewをなくすことができます。そして@FragmentArgとメンバ変数の宣言だけで勝手にインジェクションされます。同じくViewのインジェクションも@ViewByIdで可能になります。
Callbackアノテーションもあります。@AfterViewsを宣言することでそのメソッドがViewとArgumentがインジェクション後のタイミングで呼ばれます。UIの初期化やパラメータを用いる処理に使いましょう。@Clickは今まで非常に面倒だったイベント設定が楽になります。

このように簡単な使い方ですが非常に効率的かつ安全なコードが作成できます。また、パーフォーマンスも落ちることはありません。上記で紹介したアノテーション以外にもたくさんありますので詳しくはAnndroid Annotaionsのドキュメントを参考してください。

最後に

Java言語の仕様上、そしてAndroidフレームワーク構成上いろんなところで無駄が発生したりしますが、検証済みのライブラリを用いることでかなりのコストを節約することができます。今回はご紹介していませんがJava8のlambda式を導入することもできます。これらの方法を使うことで無駄な実装がなくなりますし、また洗練されたコードが書けるためAndroid開発を満喫することができたりします。

次の機会では現段階でJavaを用いたAndroidの究極開発だとも言えるlambda式を利用したAndroid開発に関してお会い出来ればと思います。

最後まで読んでいただきありがとうございました。