haXe NME通过JNI调用Android

14 篇文章 0 订阅
13 篇文章 0 订阅

haXe中的JNI概念

首先澄清一个概念问题,NME中的JNI接口和java中的含义并不相同,java中的JNI是java调用本地C/C++代码的标准接口,而haXe中的JNI则正好相反,是用haXe在Android目标平台调用java代码。当然,意义上也说得通,因为从haXe和Android目标的关系来说,Android自带的java运行库反而是native的嘛,呵呵。

 

nme.JNI类的使用

haXe NME调用java方法是通过nme.JNI类实现的,JNI类中只有两个静态函数createStaticMethod和createMemberMethod。看看函数的说明:

 /**
  * Create bindings to an class instance method in Java
  * @param className  The name of the target class in Java
  * @param memberName  The name of the target method
  * @param signature  The JNI string-based type signature for the method
  * @param useArray  Whether the method should accept multiple parameters, or a single array with the parameters to pass to Java
  * @return  A method that calls Java. The first parameter is a handle for the Java object instance, the rest are passed into the method as arguments
  */
 public static function createMemberMethod(className:String, memberName:String, signature:String, useArray:Bool = false):Dynamic;
 
 /**
  * Create bindings to a static class method in Java
  * @param className  The name of the target class in Java
  * @param memberName  The name of the target method
  * @param signature  The JNI string-based type signature for the method
  * @param useArray  Whether the method should accept multiple parameters, or a single array with the parameters to pass to Java
  * @return  A method that calls Java. Each argument is passed into the Java method as arguments
  */
 public static function createStaticMethod(className:String, memberName:String, signature:String, useArray:Bool = false):Dynamic;


可以看到,参数列表完全一致,这两个函数的区别就在于,memberMethod在调用时,第一个参数必须是java对象的句柄(handler),它也就是java方法中的this引用。

具体的代码例子请看下面代码:

public static function getBuffer():Dynamic
{
    if (_getBuffer_func == null)
        _getBuffer_func = nme.JNI.createStaticMethod("com/company/product/HaxeStub", "getBuffer", "()[I", true);
    var a = new Array<Dynamic>();
    return _getBuffer_func(a);
}

上面的haXe函数将调用java类com.company.product.HaxeStub的静态方法"int[] getBuffer()"。

注意:

1. 类名中的'.'必须用'/'代替,NME自带的例程中这里写错了(那个例程已经很久没有更新了)。

2. 所谓signature就是java方法的签名,也就是方法原型的表述方式,这是Java虚拟机的标准。上面的方法签名说明getBuffer的原型是int[] getBuffer()。具体细节这里有篇不错的文章可以看看http://blog.csdn.net/freedom2028/article/details/7772141

3. createStaticMethod返回的Dynamic对象就可以当做一个普通的haXe函数来调用了,haXe会自动帮你对参数和返回值做java <-> haXe的转换。

4. 如果java方法的返回值是对象类型,你可以获得该对象的“句柄”(handler),你可以在haXe代码中传递句柄对象,也可以以它为参数调用其它java的静态方法或成员方法。

5. java类的构造方法也可以被调用,它实际上是作为一个名为"<init>"的普通静态方法处理的,返回值当然就是创建的新对象的句柄。"<init>"实际上也是构造方法在JVM中的标准名,对应的"<clinit>"则是类的静态初始化方法的标准名(就是java中 static { ... }这样的代码块,实际也是作为一个java静态方法处理的)。

 

使用工具从java类自动生成haXe的对应“存根”类(Stub)

这两个函数使用起来并不复杂,但是实际使用中却比较麻烦,因为这里都是用字符串来表述java的类和参数、返回值类型的,没有java编译器帮你找到错误,所以比较容易因为笔误导致运行期错误。

还好NME提供了工具帮我们生成类似上面的Stub类:

使用命令"nme generate -java-externs <java class文件路径> <输出目录>"就可以根据一个java class文件(注意不是根据源文件)自动生成该类的对应haXe类了。

具体例子:应该在java类文件的根目录下运行此命令,比如:

D:\work\myhaxeproject\release\android\bin\bin\classes>nme generate -java-externs com/company/product/HaxeStub.class outputdir

注意:

1. 类名的路径中不要使用反斜杠而要用正斜杠;

2. 此工具在相对路径处理上还有些问题,输出的haXe类中类名字符串中会错误的使用'.'而不是期望的'/',你需要手动修正。不过还好,也算减轻了不少敲代码笔误的可能性了。当然也可能是我使用的方式不对,如有错误请大家指正。

 

调用涉及Android本地UI的方法

调用不涉及Android UI的方法用上面的代码就可以了,但是,如果被调用方法涉及到Android的UI系统,则需要特殊处理。因为haXe的主逻辑和Android的UI渲染运行在不同的线程中,如果你在haXe的线程中调用Android UI相关代码,就会导致线程同步错误。

比如,启动一个Activity,显示一个Toast,都属于UI类方法。

具体也很简单:把需要运行在Android UI线程中的代码用一个回调函数包起来,然后使用nme.Lib.postUICallback()方法来调用即可,看下面的例子:

nme.Lib.postUICallback(function() { _startActivity(className, requestCode); });

上面代码中_startActivity()就是通过createStaticMethod获得的java方法。


使用JNI的一些注意点

1. 对于需求Object类型作为参数的方法,如果传入一个String对象,会发生错误,大概是NME JNI把String特殊处理了,却没考虑到String在java中也是个普通的类。这个问题影响到所有泛型类,因为泛型类经过javac编译器的类型擦除后,泛型参数实际上都会被作为Object类处理。我已经报告了此Bug,估计下一版本可以修正了。

2. 虽然理论上来说JNI应该能随意和java互动,但实际情况是:haXe的JNI接口出现的时间并不长,用的人也还不多,目前可能还有其它bug,但进行一些基本的调用是没有问题的。因此我的建议是不要搞太复杂的JNI调用,尽量把复杂度包装在纯java代码和纯haXe代码中,而保持两者的接口尽量简单。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值