ラベル AndroidAdventCalendar の投稿を表示しています。 すべての投稿を表示
ラベル AndroidAdventCalendar の投稿を表示しています。 すべての投稿を表示

2012年12月28日金曜日

drawable.xmlで遊んでみる #androidadvent2012

これはAndroid Advent Calendar 2012の12月28日<表>のエントリです。

@kinnekoさんの<裏>記事もどうぞ。
Supersonicで自前のGoogleMusicを実現する http://d.hatena.ne.jp/kinneko/20121228/p1



こんにちは。最近、公私共に全然Androidの開発やってない@mstsskです。

昨年のAndroid Advent Calendar 2011では、先にJPPの太鼓持ちjsonというテーマを決めていたので、「Androidアプリで使えるJSONライブラリ比較」という記事を書きました。

ですが、今回は記事に出来るような事がなーんにもない状態で、勢いでAdvent Calendarに参加を決めちゃいました。

ううむ。どうしよう…

そうだ! Androidと言えば、drawableがある。Shape Drawableを使えば、画像ファイルを用意せずともxmlの記述だけで画面解像度に依存しない図形を描画できる。 #小芝居
でも、描けるのはあくまでも簡単な図形だけらしい… そこで、drawable.xmlで絵が描けるか試してみました。


ドロイド君を drawable.xml だけで描いてみた



はい。読み飛ばした方、こんにちは。

いかかでしょうか。ドロイド君くらいならxmlの記述だけで描けてしまいます。
colors.xmlだけは作りましたが、1ソースで済ませるという縛りでやってみたので大分冗長になっちゃってるのはご愛嬌。
まぁ、ちゃんと分けたとしてもあまり綺麗にはならなそうだったというのもありますけど。




ふー。終わった終わった。これで肩の荷が降りたわー。あー良かった。

ん。そういえば、他にも同じ事やってる人いたりしないよな… まさかな…


………………

[drawable ドロイド君][検索]

…………

検索結果に…

……

XML Drawable onlyでドロイド君を描いてみた - ReDo



だだ被りじゃねぇか!!!!! ( Д ) ゜ ゜

XML Drawable onlyでドロイド君を描いてみた http://greety.sakura.ne.jp/redo/2011/12/xml-drawable-only.html via @youten_redo

しかも、Advent Calender主催者の、Advent Calender関係ない、1年も前のエントリと。


このままじゃヤバい。ヤクい。これは、何かしら差別化しないと…

そうだ! 以前にやったこれをdrawable.xmlでやってみたらどうだろう!


というわけで↓

わかめねこを drawable.xml だけで描いてみた


はい、結局いつものネタに走りました。
drawable.xmlになってもわかめねこのプリチーさは変わりませんね。



解説のようなもの

めんどくさい満足したので、これで終わりにしてもいいんですが、一応解説。

viewを内包せず、全部1つのdrawable.xmlの中でshapeで済ませるにあたって、ミソになったのが以下
  1. layer-listのitemの子要素として直接shapeを書ける
  2. 最も外側のitemを基準にしたpaddingによる相対的なサイズ・位置の指定
  3. itemとshapeの間にrotate要素を入れて回転を設定
  4. ovalのshapeはstrokeのdashGap,dashWidthを調整すれば円弧が描ける


layer-listのitemの子要素として直接shapeを書ける


item要素のandroid:drawable属性で別ファイルのdrawableを指定しなくても、子要素としてshapeを記述できます。


最も外側のitem要素を基準にしたpaddingによる相対的なサイズ・位置の指定


item要素のandroid:top,bottom,left,rightの各属性は、各辺ごとに一番外側の部分からの距離(padding)を指定します。
そこで、適当なsize指定をしたitem要素を外枠として、その内側に収まるように他のitem要素のpaddingを記述して位置や大きさを指定しました。
各itemのpaddingを、外枠にしたitem要素のsizeより大きくなるようにしてしまったり、item要素の大きさが負になるようなpadding指定をしてしまうと、全部のitemが思っきり崩れます。

これは、ソースからドロイド君の胴体部分と外枠部分の記述だけを抜き出したものです。


itemとshapeの間にrotate要素を入れて回転を設定


shapeを回転させるには、item要素の直下にshape要素を置かずに、 item → rotate → shape という具合にrotate要素を挟み、その属性で回転角度・回転軸(pivot)を指定します。


ovalのshapeはstrokeのdashGap,dashWidthを調整すれば円弧が描ける


shapeは本来は、矩形・丸・線・円の4つの簡単な図形しか描けませんが、無理やり円弧を描くこともできます。
stroke要素のdashGap属性,dashWidth属性の記述によって、ある程度は円の切れ方を指定できるので、それを利用します。

これは、わかめねこの鼻の部分のソースです。
2つの円弧をずらして配置し「ω」という形にしています。

これらの手段を組み合わせれば、わかめねこの様なイラストもdrawable.xmlで描けてしまう、という訳です。


Gingerbread以前では?

ちなみに、これらのコードはICS以降向けです。
Gingerbread以前のバージョンでも動きますが、rotate指定の回転の基準点が全く違う箇所になる様で、rotateを使っているshapeがずれてしまいます。※ Honeycombで試してない(てへぺろ


上記はレイアウトエディタのスクリーンショットですが実機でも同じ様な表示となります。
左アンテナは上にずれ、右アンテナは下にずれて胴体の下に隠れてしまっています(マウスカーソルのある辺りにあります)。

ちゃんと確認してはいないんですが、どうやら以下のような違いがあるのでは、と考えています。
ICS以降
paddingの内側の描画されている範囲の左上が回転軸の基点
Gingerbread以前
paddingの外側の一番大きい要素の左上が回転軸の基点



まとめ

勢いだけで、大分役に立たない記事と相成りました。

ただ、png画像など用意せずにxmlの記述だけでもここまで描けるというのがわかっていただけと思うので、今後アプリを作ったりデザインしたりする方々には是非覚えておいていただきたいです。上手く使えば様々な画面解像度への対応が捗るんではないでしょうか。今後もハードウェアの技術向上は続きますから、HTC J butterflyのxxhdpiみたいなショックが来るかも知れませんからね。

「Androidもうええねん」なんて声も聞こえますが、まだまだAndroidは続きますよ!
オレはようやくのぼりはじめたばかりだからな。このはてしなく遠いAndroid坂をよ…

さて、明日は @awwa500 さんと @takke さんの担当です。
何故か新年までカウントしていくAndroid Advent Calender 2012。どうぞ大晦日の大トリ記事までよろしくお願いします。



今回作ったもの

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の採用を決めるような魔導書レベルの記事は書けませんよ流石に