Android NDK最新版でOpenGL ES 2.0をサポート
- - PR -
今回のテーマは「AndroidでJNI(Java Native Interface)を使用したアプリの高速化」です。C/C++やOpenGL ES(※)といったネイティブコードを使うツールなどのセットは、Android NDK(Native Development Kit)として提供されていて、JNIを使用した高速化に欠かせません。
※OpenGL ES(OpenGL for Embedded Systems)
携帯情報端末や組み込み向けのOpenGLのサブセット。OpenGLは、一般的に普及しているグラフィックスプログラミング用のC/C++のAPIのこと(参考:はじめよう3D描画、BREWでOpenGL ESプログラミング)
JNIとNDKの詳細は、以下の記事をご確認ください。
そんなAndroid NDKですが、先日、最新版のRevision 3がリリースされ、OpenGL ES 2.0がサポートされるようになり、さらにグラフィック描画機能が強化されました。
ちなみに、r3(Revision 3)リリースに伴い、いままでのNDKのバージョン、Android 1.6 NDK Release 1(1.6r1)はAndroid NDK r2(Revision 2)に、1.5 NDK Release 1(1.5r1)は同じくr1(Revision 1)に呼び方が変わっているので、ご注意ください。
■ 同じサンプルをJNIで高速化した結果を動画で確認
今回の題材として、前回の「Android 2.1の新機能「Live Wallpaper」で作る、美しく燃える“待ち受け”」のサンプルを使用して、燃えるエフェクトを高速化します。下記の動画で高速化されていることが確認できますね。
| 最初は、JNI高速版、次にJava版に切り替えて、再度JNI高速版に戻した動作サンプル |
今回の高速化を施したサンプルアプリは、以下よりダウンロードしてください。
そもそも、JNIってAndroidに必要なの?
Webアプリケーションを開発するJavaプログラマにとって、JNIはあまり使用しない機能ではないかと思います。実際Javaという言語および実行環境はとても優秀なので、Javaだけで事足りてしまうためです。
今回は、目的があってJNIを使用するのですが、その前にAndroidでJNIを使用するメリットとデメリットを見てみましょう。
| 表1 JNIのメリットとデメリット | ||||||
|
メリットはC/C++などで実装された既存のライブラリを利用できること、パフォーマンスを向上できることです。Android 2.1のDalvik VMには、JITは搭載されていないため、パフォーマンス向上は顕著です。デメリットはプラットフォーム(CPUのアーキテクチャ)に依存してしまうことが挙げられます。
現時点でAndroidのプラットフォームのほとんどはARMアーキテクチャを採用していますが、x86をはじめ、さまざまなCPUのプラットフォームがサポートされ始めています。
今回のサンプルは、ARM向けのネイティブライブラリがアプリに組み込まれた形になっています。このネイティブライブラリはARMアーキテクチャ以外で動作できないので、必要であれば「System.getProperty("os.arch")」で取得した値に「arm」または「ARM」が含まれているかどうかで判断します。含まれていない場合は、ネイティブライブラリをロードせず、代替手段を講じるのがいいでしょう。
コラム 「難しいJNIのメモリ管理に対する戦略」 |
JNIの実装はC/C++を使用することになるのですが、C/C++を使用するに当たり、問題なのがメモリ管理です。以下に、JNIにおけるメモリ管理の戦略を紹介します。・JNI_OnLoad()、JNI_OnUnload()JNI_OnLoad()は、ネイティブライブラリがロードされた際に呼び出される関数で、JNI_OnUnload()関数はネイティブライブラリを含むクラスローダがガベージコレクタで回収される際に呼び出されます。ネイティブライブラリで確保したメモリは、JNI_OnUnload()関数で解放する方法が考えられます。ネイティブ側の作業領域やシステムで共有可能なメモリなどの解放に向いています。・Object#finalize()ネイティブ側で確保したメモリは、そのアドレスをJava側のフィールドにintとして保持しておき、対象のインスタンスがガベージコレクタで回収される際に、finalize()メソッドで解放する方法が考えられます。ネイティブ側の処理がJavaのインスタンスに連動する場合に向いています。どちらのケースにしても、メモリ以外にリソースの解放も必要です。リソースの解放とメモリの解放は、必要となるタイミングが異なる場合があるので、注意してください。 |
アプリのどこが重いのかを調べ、ネイティブ化すると…
今回の目的は、JNIを使用した高速化です。ですから、まずどの部分の処理が重いのか調査します。
public void draw(Canvas canvas){
synchronized (this) {
Log.d("TIME", "1:" + System.currentTimeMillis());
for (int i = 0; i < width * height; i++) {
if (seedparam[i]!= 0 && seedparam[i] > (int)((fireLevel - boost) * Math.random())) {
pallet[i] = 127;
} else if (seedparam[i] != 0) {
pallet[i] = 0;
}
}
if (boost > 0) {
boost--;
}
Log.d("TIME", "2:" + System.currentTimeMillis());
for (int i = 1; i < height - 1; i++) {
for (int j = 1; j < width - 1; j++) {
pallet[(i - 1) * width + j] = (pallet[i * width + j] +
pallet[i * width + j - 1] +
pallet[i * width + j + 1] +
pallet[(i - 1) * width + j] +
pallet[(i + 1) * width + j]) / 5;
}
}
Log.d("TIME", "3:" + System.currentTimeMillis());
for (int i = 0; i < width * height; i++) {
image[i] = color[pallet[i]];
}
Log.d("TIME", "4:" + System.currentTimeMillis());
bitmap.setPixels(image, 0, width, 0, 0, width, height);
Log.d("TIME", "5:" + System.currentTimeMillis());
canvas.drawBitmap(bitmap, 0, 0, null);
Log.d("TIME", "6:" + System.currentTimeMillis());
}
}
上記は前回のサンプルの状態のソースコードで、ところどころにログが埋め込んであります。筆者の環境でのエミュレータ上での所要時間は以下の通りです。
| 表2 筆者の環境でのエミュレータ上での所要時間 | ||||||||||||||||||
|
forループ文内でピクセル処理を行っている個所が圧倒的に遅いです。ここを切り出してネイティブ化すれば、高速化が見込めそうです。
public void draw(Canvas canvas) {
synchronized (this) {
effect(fireLevel, width, height, image, pallet, seedparam, color);
bitmap.setPixels(image, 0, width, 0, 0, width, height);
canvas.drawBitmap(bitmap, 0, 0, null);
}
}
private native void effect(int fireLevel, int width, int height, int[] image, int[] pallet, int[] seedparam, int[] color);
新しいソースコードは、上記のように、処理時間のかかる部分をすべてネイティブコードに置き換えています。Javaのみで平均1300msかかっていた描画処理が、JNIに置き換えることで平均70msになりました。
| 表3 所要時間の比較 | |||||||||
|
Javaの処理をネイティブに移植することで高速化できる、という大変良い例になったかと思います。
それでは、次ページよりJNIへの置き換え方法を詳しく見ていきましょう。
| Index | ||||||||
|
||||||||
Androidで動く携帯Javaアプリ作成入門 バックナンバー 連載インデックスへ»
- 第1回 Android Market配布を目指しEclipseでHelloWorld!
- 第2回 Androidアプリ作成の基本“Activity”とは何か?
- 第3回 ブラウザや地図、ストリートビューの基、Intentとは?
- 第4回 簡単でワクワクするAndroidウィジェット10連発!
- 第5回 Androidアプリの使いやすさを左右する5つのレイアウト
- 第6回 AndroidでSQLiteのDB操作をするための基礎知識
- 第7回 常駐アプリが作成できるAndroidの“サービス”とは
- 第8回 アプリを国際化してAndroid Marketから世界へ発信
- 第9回 Netbookにも広まるAndroidで、かつてないWeb体験を
- 第10回 Androidのホーム画面に常駐するアプリを作るには
- 第11回 Android 1.6のジェスチャーとテキスト読み上げを使う
- 第12回 SurfaceViewならAndroidで高速描画ゲームが作れる
- 第13回 iPhoneより多彩なAndroidのセンサをアプリで操作
- 第14回 Android 2.1の新機能で作る、美しく燃える“待ち受け”
- 第15回 Android NDKでJNIを使用してアプリを高速化するには
- 第16回 地図/位置情報/GPSを使うAndroidアプリを作るには
- 第17回 もはやケータイに必須のカメラをAndroidで制御しよう
- 第18回 開発者が知っておきたいAndroid 2.2新機能 12連発
- 第19回 XMLレイアウトでAndroidアプリに“設定画面”を追加
- 第20回 Androidアプリで“アニメーション”するための基礎知識
- 第21回 アニメーションでAndroidに独創的な画面エフェクトを
- 第22回 開発者が知って得するAndroid 2.3の新機能18選
- 第23回 Android 3.0の新APIで簡単ドラッグ&ドロップ実装
- 第24回 Androidの画面の大きさの違いを解決するFragments
- 第25回 Compatibility packageで2.x系でもマルチサイズ対応
- 第26回 開発者が知らないと損するAndroid 4.0の新機能44選
- 第27回 Android 4.0でアプリ開発を始めるための環境構築
- 第28回 Android 4.0で注目の顔認識をアプリに組み込むには
| ご意見、ご感想は Smart&Social 会議室へどうぞ |
| Smart&Social フォーラム トップページへ |
TechTargetジャパン
- 検索技術を使うなら知ってないと損する6つのこと (2012/2/9)
ソーシャルアプリなど大規模Webサービスや企業内システムでも欠かせない検索技術のまとめ - AWSとAndroidを直結するSDKで何ができるのか? (2012/2/3)
簡単なコーディングでAndroidアプリからAmazon S3のストレージに直接接続できるサンプルを基にSDKの使い方を紹介 - HTML5/jQuery MobileなどスマホWeb開発記事33選 (2012/1/31)
スマートフォン向けWebアプリを作るための@IT記事のまとめ。HTMLやCSS、JavaScript/jQuery自体の基礎学習記事も紹介 - iPhoneで動くARアプリを作るためのライブラリ10選 (2012/1/25)
ARToolkitをはじめ、iOS(iPhone/iPad)で使えるAR(拡張現実)を実現するためのさまざまなライブラリをサンプルやコードを交えて紹介
|
|
キャリアアップ
スポンサーからのお知らせ
イベントカレンダー
- - PR -



