在 上文中已经介绍了 AndroidJavaObject 的调用流程,本文将重点介绍 调用过程中的函数流程,在掌握了调用流程之后,分析能够进行优化的方向
调用流程
还是以官方的示例做分析 根据上文中的源码分析,统计下JNI 调用次数和 Android 端反射次数
创建对象
- JNI 调用:
- FindClass(string name)
- NewString()
- CallStaticObjectMethod()
- FromReflectedMethod()
- NewObject()
- 反射
- getConStructorID()
一次创建 AndroidJavaObject 需要五次 JNI 调用和一次 Android层的反射
执行函数
- JNI调用:
- NewString()x2
- CallStaticObjectMethod
- FromReflectedMethod()
- CallIntMethod()
- 反射:
- getMethodId()
一次函数调用需要 五次 JNI 调用和一次 Android 层的反射
函数的二次调用由于 Android 层的缓存会少一次反射
以上的统计师没有计算参数的,JNI 传递参数都是需要通过创建 JNI Array来临时保存,执行完毕之后删除
AndroidJavaClass 与 AndroidJavaObject 的区别
在Unity 代码中能够看到 **AndroidJavaClass**
是继承自 **AndroidJavaObject**
的,那是否可以在项目中只使用 **AndroidJavaObject**
,不使用 AndroidJavaClass ** ?答案是不行的**
通过查看源码能够看到,在创建 **AndroidJavaClass**
是,只有一次JNI的调用。性能要比**AndroidJavaObject**
优秀很多。
调用优化方向
常规方向
根据本文与上文的 流程分析,可以总结出以下一些方法,能够提高与 Android 端的调用效率
- 调用静态方法 使用
AndroidJavaClass
,禁止使用AndroidJavaObject
- 需要频繁调用的对象,可以缓存之后重复调用,避免频繁创建
- 调用方法参数内容避免使用 Android 端对象,例如 Application,Activity,Context,View 等,可直接在 Android端定义包装方法,从 Android 端直接获取。
- 推荐使用静态方法,而不是对象方法,避免创建Android对象
可选方向
方法参数协议
在方法的多个参数传递过程中,可以为参数传递制定一个协议,在 Unity 层将多个参数包装成一个参数,降低传递参数的数量,减少JNI 内存占用。在 Android 层将单个参数按照协议解成多个参数,再调用具体方法。
单例函数 Channel
在 Android 端 创建一个 Channel 静态类,将需要执行的 Android 方法注册其中,定一个方法,参数分别是对应的需要执行的 Android方法的 Key,和执行该方法需要的参数。
这个方案的优势是,只需要一次 JNI 的创建和一次方法的反射。之后的调用都可以通过 Key 的不同映射到对应方法执行,不需要反射执行,同时也不需要 JNI 创建对应的需要执行的对象。可以想 JNI 传递内容将到最低。