適当に、Javaのメソッドを呼び出してみる
以下は、UnityEngine.AndroidJavaObject
クラスとJavaのandroid.os.StatFs
クラスを使って、100回連続で端末の空き容量を調べるスクリプトです。(普通こんなシチュエーションないですが・・・)
hoge.cs
public int loopCount = 100;
// 毎回 AndroidJavaObjectを生成 & 破棄
public void CreateAndDispose ()
{
int blockSize = 0;
int availableSize = 0;
long startTime = DateTime.Now.Ticks;
for (var i = 0; i < loopCount; ++i) {
using (AndroidJavaObject statFs = new AndroidJavaObject( "android.os.StatFs", Application.persistentDataPath)) {
blockSize = statFs.Call<int> ("getBlockSize");
availableSize = statFs.Call<int> ("getAvailableBlocks");
}
}
long endTime = DateTime.Now.Ticks;
var duration = new TimeSpan (endTime - startTime);
Debug.Log(string.Format ("Create Once {0} msec\n {1}", duration.TotalMilliseconds, (blockSize * availableSize)));
}
// 最初にAndroidJavaObjectを一個だけ生成 あとは使い回してCall
public void CreateOnce ()
{
int blockSize = 0;
int availableSize = 0;
long startTime = DateTime.Now.Ticks;
AndroidJavaObject statFs = new AndroidJavaObject ("android.os.StatFs", Application.persistentDataPath);
for (var i = 0; i < loopCount; ++i) {
blockSize = statFs.Call<int> ("getBlockSize");
availableSize = statFs.Call<int> ("getAvailableBlocks");
}
statFs.Dispose ();
long endTime = DateTime.Now.Ticks;
var duration = new TimeSpan (endTime - startTime);
Debug.Log(string.Format ("Create Once {0} msec\n {1}", duration.TotalMilliseconds, (blockSize * availableSize)));
}
// AndroidJavaObjectのメソッド呼び出しをキャッシュしてみた
public void CreateTinyAndroidObject ()
{
int blockSize = 0;
int availableSize = 0;
long startTime = DateTime.Now.Ticks;
TinyAndroidJavaObject statFs = new TinyAndroidJavaObject ("android.os.StatFs", Application.persistentDataPath);
int getBlockSizeHash = statFs.LoadIntMethod ("getBlockSize");
int getAvailableBlocksHash = statFs.LoadIntMethod ("getAvailableBlocks");
for (var i = 0; i < loopCount; ++i) {
blockSize = statFs.CallInt (getBlockSizeHash);
availableSize = statFs.CallInt (getAvailableBlocksHash);
}
statFs.Dispose ();
long endTime = DateTime.Now.Ticks;
var duration = new TimeSpan (endTime - startTime);
Debug.Log(string.Format ("Tiny {0} msec\n {1}", duration.TotalMilliseconds, (blockSize * availableSize)));
}
TinyAndroidJavaObject.cs
using UnityEngine;
using System.Collections.Generic;
using System;
public class TinyAndroidJavaObject : AndroidJavaObject
{
protected readonly Dictionary<int, IntPtr> _methodPtrCacheMap = new Dictionary<int, IntPtr> ();
public TinyAndroidJavaObject (string className, params object[] args) : base(className, args) { }
// 使いたいメソッドのMethodIDをキャッシュしておく
public int LoadIntMethod (string methodName, params object[] paramSamples)
{
// オーバーロードを考えると、メソッド名だけじゃなく、引数の型もハッシュ計算に入れたほうが良さげ
int methodNameHash = methodName.GetHashCode ();
if (_methodPtrCacheMap.ContainsKey (methodNameHash)) {
return 0;
}
IntPtr ptr = AndroidJNIHelper.GetMethodID<int> (m_jclass, methodName, paramSamples, false);
if (ptr == default(IntPtr)) {
return 0;
}
_methodPtrCacheMap [methodNameHash] = ptr;
return methodNameHash;
}
public int CallInt (int methodNameHash, params object[] args)
{
if (_methodPtrCacheMap.ContainsKey (methodNameHash)) {
if (args == null) {
args = new object[0];
}
jvalue[] array = AndroidJNIHelper.CreateJNIArgArray (args);
try {
return AndroidJNI.CallIntMethod (m_jobject, _methodPtrCacheMap [methodNameHash], array);
} finally {
AndroidJNIHelper.DeleteJNIArgArray (args, array);
}
}
return 0;
}
protected override void Dispose (bool disposing)
{
_methodPtrCacheMap.Clear ();
base.Dispose (disposing);
}
}
CreateAndDisposeとCreateOnceとCreateTinyAndroidObjectの実行時間の比較結果
環境は、2012年モデルのNexus7
-
CreateAndDispose();
=> 35ms 前後 -
CreateOnce();
=> 8ms 前後 -
CreateTinyAndroidObject();
=> 1ms 前後
そこそこ早くできそう
重い重いと言われている、UnityからのネイティブAPI呼び出しだけど、頑張ればそれなりに軽減できるっぽい。
ただし、安全なのかはわかりませんけどね!