苏州区网站建设,wordpress自动添加标签,各类网页设计,网站视频源码地址一#xff1a;NDK的函数调用时出现 “UnsatisfiedLinkError : 函数名” 这样的异常
解决办法#xff1a; 网上能找到的提醒无一不是让你去仔细检查NDK中的函数命名是否正确#xff0c;也就是“JAVA_调用该函数的JAVA类名#xff08;完整路径区分大小写#xff09;_函数名…一NDK的函数调用时出现 “UnsatisfiedLinkError : 函数名” 这样的异常
解决办法 网上能找到的提醒无一不是让你去仔细检查NDK中的函数命名是否正确也就是“JAVA_调用该函数的JAVA类名完整路径区分大小写_函数名”这样的JNI格式。然而我在确定这个命名准确无误后仍得到这个异常。 为什么呢反复捣鼓后幡然醒悟我用的是C文件后缀用.cpp按C来编译。 由于JNI是采用了C风格的函数命名所以如果用C编译则必须记得在每个函数前加上extern C的标记。这个东西记得NDK的docs里面有提到现在找不到在哪了那些docs只能自己一份份地看实际写的时候还是忘了。
二进行jfieldID和jmethodID的cache时不能转化为global reference 解答local/global reference这些概念只是跟jobject的指针相关包括它的派生类如jclass因为这些指针所指空间如果为local的话则会在作用域结束时被回收所以做cache时才需要转化为global reference。 而jfieldID和jmethodID查看头文件便可知与jobject无关只是一些native的空间分配因此与local/global这些JNI加入的新概念无关按C/C的做法去cache即可。
三为何调用GetFieldID时传入参数如果为类则必须按照这种格式“Ljava/lang/String;”而调用FindClass时则直接“java/lang/String即可 解答因为GetFieldID函数要解析类型签名这些签名既包括int、bool这些原生类也包括String或者自定义的JAVA类因此需要对String这些需要指定类路径的设计一个额外的格式以作为区分估计可以提高解析签名的效率。 而FindClass函数不针对int、bool那些原生类这些在C中不算class因此无需要加入这种格式上的区分。
四能够创建的local ref的数量是有限的吗如果要创建一个比较大的jobjectArray并返回怎么办 解答local ref的数量的确是有限的这个限制大概比512小一点点JNI背后是用一张表来记录你创建的每个local ref这个表有长度限制意味着你调用一个native函数时不能创建超过这个数量的local ref。 于是你试图访问/返回一个超过该限制长度的jobjectArray时就很郁闷了不过这是因为你对Get/SetObjectArrayElement这一对函数产生了一个误解。以SetObjectArrayElement为例你传入一个local ref的参数看上去是把这个local ref给放到了你的array中实际上这个local ref并未放进去放进去的只是ref指向的内容本身所以这个函数执行后那个local ref就可以删除了所以就不存在长度限制的问题。同样GetObjectArrayElement每次会新产生一个local ref所以你用完要立刻删掉不然就可能超过local ref的数量限制。
这个误解应该很普遍吧其实Sun官方的JNI Spec文档中都有写范例代码也都这么做了不过还是强调得不够第一次写的时候还是很容易被表面代码所误导。
五GetStringRegion和GetStringUTFRegion的特别提醒
这两个函数都有一个len的参数表示Unicode字符的个数但是要注意这两个函数会在copy完字符串后自动把数组的len1个元素赋为0因此分配空间时就要分配len1否则嘛。。你的程序随时crash当你执行delete[]时
六如何在 JNI 中打 Log
第一步在对应的mk文件中加入:LOCAL_LDLIBS : -llog 第二步在要使用LOG的cpp文件中加入
#include android/log.h
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, keymatch, __VA_ARGS__)第三步这样就可以使用了LOGD(我要看到的调试信息^_^);
这样在logcat端看到的输出是
D/keymatch 32:我要看到的调试信息^_^如果想改变输出中的各项内容可以参考相应颜色的标示比如如果想定义LOGE就可以把上面的ANDROID_LOG_DEBUG改成ANDROID_LOG_ERROR同理LOGI神马的也都以此类推
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, ProjectName, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , ProjectName, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO , ProjectName, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN , ProjectName, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , ProjectName, __VA_ARGS__)当然如果不嫌麻烦也可以直接使用__android_log_print函数而不define定义LOGxxx
另外有文章称此方法在编译动态库的时候可能会出问题会提示cannot find -llog的错误。意思是找不到liblog.so这个库文件。因此需要改成 LOCAL_LDLIBS: -L$(SYSROOT)/usr/lib -llog 才可以正常编译。但是我这边编译动态库的时候好像不用这样改也行没发现编译时提示“cannot find -llog”的错误。