AndroidJavaObject 调用流程和优化方向

1,365 阅读2分钟

在 上文中已经介绍了 AndroidJavaObject 的调用流程,本文将重点介绍 调用过程中的函数流程,在掌握了调用流程之后,分析能够进行优化的方向

调用流程

还是以官方的示例做分析 image.png 根据上文中的源码分析,统计下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 ** ?答案是不行的** image.png 通过查看源码能够看到,在创建 **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 传递内容将到最低。