テイルズ・オブ・高速Androidプログラミング

本日の記事のタイトルはホッテントリメーカーで生成されています。

http://pha22.net/hotentry/

これで141userゲットだぜwwwww

それはともかくとして、今日はたまにはプログラミングのお話です。タイトルから分かる通り、Androidで高速に動作するアプリケーションをプログラムする方法について説明いたします。

Androidでサクサク高速に動作するプログラムを書くための5つの方法

・まずは自分の見たことだけを信じなさい
AndroidはJavaなので基本的にJavaの高速化手法が使えます。クラスの生成を抑制する、ガベージコレクションを抑制するといった基本はAndroidでも当然のごとく使えます。しかし・・・特定の機種でだけ遅いとか、なんかよくわからないけど遅い・・・ということがよくあるわけです。そんな時はまず見えるようにしましょう。そこでプロファイラの出番ですね。Android開発では簡単にプロファイラが使えるので使ってみましょう。
eclipse ならウィンドウ→ビューの表示→その他→Android→DeviceでDeviceビューを追加します。
あとは、プログラムをデバッグ実行しつつプロファイルを開始したいタイミングでこのボタンを押します。そして、やめるタイミングでもう一度押すとtraceviewという プロファイラが開きます

どの処理が重いかは一目瞭然ですね。Excl CPU Time(そのメソッド単体でかかった時間)でソートして、重い処理から潰して行きましょう。ちなみにIncl CPU Timeはそのメソッドでかかった時間(そのメソッドで呼んだメソッドでもかかった時間を含む)です。

・重いクラスはキャッシュ汁!

Android開発ではキャッシュ効率が非常に重要です。それはなぜかというとAndroid端末の特性を知ってれば多分分かると思いますが、Android端末というのは「CPUはまあへっぽこ、GPUは同様にへっぽこ、しかしメモリだけは1GBとかPC顔負けの容量を積んでいる」わけです。へっぽこな端末でも256MBくらいはメモリ積んでいるので、メモリをジャブジャブ使うようなプログラムを書くのが基本的に速いです。しかもガベージコレクションを抑制できるというメリットもあったりします。Bitmapやネットワークから得られたデータ、OpenGLのテクスチャ、読み込んだテキストなど生成にコストの掛かるクラスは必ずHashMapなどでキャッシュしましょう。ただし、問題があってAndroidではメモリ不足になるとさくっとプログラムが落ちるので適度に開放しないといけないですが。SoftReferrenceを使うという手もあるようですが
http://labs.techfirm.co.jp/android/cho/2142
Androidでは、かなーり早い段階でSoftReferrenceが解放される気がするので、ギリギリまで保持しておきたいキャッシュはどうすればいいんでしょうかね。落ちるの覚悟で、延々メモリーリークさせておくのも手か!?
ちなみに、メモリが1GBあるからって、DalvikHeapは16MBとかしか使えないので、やっぱネイティブにメモリ領域を取るBitmapくらいしかキャッシュできるのはないかもね。 それかNDK使うか?

ところで、昨年のGDD参加権を争うためのスライドパズル問題を解くときの模範解答としてどこかのブログであげられていたのも、キャッシュを汁だった気がします。スライドパズルなんて要はゴール←ゴール一歩前←・・・と任意の状態から一意のゴールへの道筋が決まるので、解法を全部キャッシュし終わればO(1)で解けてしまうのでしょうか。

・非同期処理・マルチスレッドを使う!

Androidでは基本的にマルチスレッドでプログラムを書いていきます。でもこれの同期処理が正直難しすぎる・・・。しかも、OpenGLやUIクラスはシングルスレッドでしか動作しないので、そういった部分の同期処理も更に大変であるという。

一つクラスを紹介してみるとCopyOnWriteArrayList,CopyOnWriteArraySetとかですかね。ただのArrayListなのですが、必ずコピーに対して書き込みをしてくれます。マルチスレッドでの同期処理を気にせず配列にアクセスできます。あと私はずぼらなので高速列挙中に配列の中身を書き換えたりしてConcurrentModificationException出してしまったりするのですが、それを抑制する効果もあります。ただーし、このクラス相当に書き込みが遅いです。読み込みもArrayListより微妙に遅いんですよね。ただの配列使うか、それとも手抜きするか・・・。マルチスレッドプログラミングは難しいが、得られるUser Experienceは大きいのでこういう遅い同期クラス使ってでも実装するべきとは思いますが。

ところで、Android2.3とかのマルチスレッドは並列に動いていないんじゃないんですかね。

同じマルチスレッドプログラムを上GALAXY nexus(Android4.0)と下T-01D(Android2.3)で実行してプロファイルしたものですが、拡大してみるとT-01Dのほうは、交互に実行しとるだけですね・・・。CPUはデュアルコアなのですが、Android2.3ではデュアルコアに最適化されていないのか。

・エフェクトでごまかす!

なんか動いてれば重いようには見えないよ!

・神に祈る

最後は結局機種依存高すぎなので、神に祈るしかないの。ワーイ。

あとこのへんもチェックしておくと幸せになれます
・デバッガは殺してみる→デバッガが接続されているとアホみたいに重くなる場合があるので、おもむろにUSBケーブルを引きぬいて動作させてみましょう。
・再起動してみる→悩んだら再起動は大原則
・そもそもプロファイラが接続されてると重くなる場合も・・・最後に頼れるのは昔ながらのログ出力方式だったりする。ナンダッテー。

(´Д`)ハァ…もうもっさりでいいよね。

まあ、愚直なアルゴリズムの高速化よりも、エフェクトとか非同期処理でごまかす手法のほうがAndroidでは効果がある気がします。プログラマーは常に手抜きをしないといけないのです。迷路を解くプログラムが必要だからって、A*アルゴリズムや幅優先探索なんてしなくていいのです。それよりはのんびりといてる間に表示するかっこいいエフェクトを用意してくれたまへ。スライドパズルの問題なんて解かなくていいのです。答えを全部予め解いておいて、メモリ上に解法を全部キャッシュしておけばいいのです。難しい問題を解くためのニューラルネットを利用した人工知能のプログラムなんて組まなくていいのです、「教えてgoo!」にその問題をカキコするプログラムを用意すればいいのです。やったねタエちゃん、デスマが増えるよ!

しかしいい加減日記に書くネタが・・・。何か面白そうなイベント情報ください。最近毎日定時に帰っていて、あと10日で会社に勤めだしてから初の残業ゼロ達成なのですが・・・。でも暇なのも暇なのであんまり良くないねえ。退屈は人を殺す、あるいは退屈が人を殺させるのか。

タイトルとURLをコピーしました