2011年12月9日金曜日

Androidアプリで使えるJSONライブラリ比較

これは、Android Advent Calendar 2011の12月9日エントリです。



「Androidはオワコン」なんて話が聞こえてくる昨今、いかがお過ごしでしょうか?
HT-03A以来のAndroidユーザーとしては寂しい悲しい限りです。発売後のこんな頃や、こんな頃が懐かしいですね。

ですけど、街中を歩くと、多くの人がAndoid機を持っているのがわかります。
REGZA Phoneとかよく目に付きますね。デカイし。

それに、Andoid機を買って初めてプログラムしてアプリを作ってみた学生さんとか、Andoid関係のお仕事の話とか結構聞こえてきます。
今後もそういうのは続いていくんじゃないでしょうか。

そして、趣味か仕事かを問わず、Webアクセスしたりするアプリの場合、APIを叩いてJSON形式のデータをパースしなきゃいけないことが多々あると思います。
そこで、JSONのライブラリをいくつか簡単に比較してみました。
下3つは使い方がよくわからんかったので、参考に並べただけです(汗
言い換えれば、いきなり持ってきても取っつきやすいものだけ紹介。



パース・エンコードの処理の計測には、自分のタイムラインのjsonを1M分繋げたファイルを使いました。/res/raw/からファイルをInputStreamで取得して使用。
計測に使った機種はXperia Ray

JSONIC

国内ではオーソドックスなんじゃないかと勝手に思っているライブラリです。
ただ、上表の通り速度は見劣りします。
比較的少ないコード量でかゆい所に手が届くようになってますけど、proguardでの難読化に失敗するので、それが解決出来ないとAndroidアプリで使うのはつらい。
使用例:

// パース。第2引数でクラスを指定しない場合、戻りはObjectになるが、中身はArrayListかLinkedHashMap。
InputStream is = ほげ;
Hoge[] hoges = JSON.decode(is, Hoge[].class);

// シリアライズ
String json = JSON.encode(hoges);


google-gson

この記事書こうと思って調べるまで存在を知りませんでした。正直すまんかった。
パース速度は爆速。シリアライズは最遅
なんなんだ。いったいなんなんだお前。
シリアライズ時に、型指定を省略すると更にアホほど遅くなります。
POJOでないクラスのフィールドに対応させるには、JsonSerializerとJsonDeserializerインターフェースを実装します。
proguardを使う場合、JSONをマッピングするPOJOクラスを難読化から除外する設定が必要です。
使用例:

// パース。第2引数で必ず型を指定する必要がある。Mapとか指定してもとりあえずは動く。JSONIC同様に、ArrayListかLinkedHashMapのインスタンスが返る。
InputStream is = ほげ;
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
Hoge[] hoges = new Gson().fromJson(reader, Hoge[].class);

// シリアライズ。第2引数の型指定は省略できるが、そうすると激遅。
String json = new Gson().toJson(hoges, Hoge[].class);


JsonPullParser

ファイルサイズが超軽量!
しかし、特色は軽量であることより、指定したPOJOクラスのパース/シリアライズ処理クラスをビルド時に自動生成する事だろう。それ故に、パースとシリアライズ共に安定して高速な処理を実現しています。
逐次処理も出来るし パースもシリアライズも早い。凄いぞ強いぞ僕らのJPP
ただ、パーサークラスを生成させるPOJOクラスとそのフィールドにアノテーションをいちいち付けなきゃいけないのはちと面倒。
POJOでないクラスのフィールドに対応させるには、TokenConverterを実装します。参考として以前に試しに書いてみたDateConverterをどうぞ。ええ、SimpleDateFormat使っちゃってるのでスレッドセーフじゃありません(最近知りました)。
使用例:

// パース。Hogeクラスの専用パーサーとしてビルド時に自動生成されたHogeGenクラスを使用
InputStream is = ほげ;
List<Hoge> hoges = HogeGen.getList(is);

// シリアライズ。直接文字列を返す手段はサポートされておらず、Writerクラスを経由する。
StringWriter sw = new StringWriter();
HogeGen.encodeListNullToNull(sw, hoges);
String json = sw.toString();


半分くらい深夜のテンションで書き殴りましたが、いかがでしょうか。
多分コレをまっさきに読むであろうAndroidersよりも、いつかググってたまたまやってくる人向けの内容になりました。

Androidを好きになってくれるエンジニアが増えてくれることを願って。


私信:読んだ人が失禁して泣いてパンツを洗いながらJPPの採用を決めるような魔導書レベルの記事は書けませんよ流石に

1 件のコメント:

匿名 さんのコメント...

すばらしいっす!