我的应用程序调用本机库,然后在本机库中调用Java代码。我有调用本机库正常工作(我很确定),但它没有告诉我它在尝试从C文件中调用它时找不到Java函数。
应用程序甚至没有崩溃,没有弹出窗口告诉我它意外关闭,它只是闪烁黑屏并且没有任何反应。
我试图重现的代码最初是用C for Palm Pilot制作的,现在正被转移到Android设备上。这是C中的原始调用我试图复制...
InitRelay(Changeit,getit,putit,flushit,delayit);
上面调用中的参数是函数名称,函数如下:
void Changeit(WORD baud){
ChangeRate(baud);
}
extern Boolean ChangeRate(UInt32 baud)
{...}
Int16 getit(UInt16 t) {...}
void putit( BYTE p ) {...}
void flushit(void){...}
extern void delayit( UInt16 wait ) {...}
这是我的.c
文件中显示的InitRelay:
BYTE __stdcall InitRelay(fp_setbaud _setbaud, fp_get _get, fp_put _put, fp_flush _flush, fp_delay _delay){
RelayAPI_SetBaud=_setbaud;
RelayAPI_get=_get;
RelayAPI_put=_put;
RelayAPI_flush=_flush;
RelayAPI_delay=_delay;
....
}
上面显示的参数在我的.h
文件中是typedefed:
typedef void (__stdcall *fp_setbaud)(WORD);
typedef short (__stdcall *fp_get)(WORD);
typedef void (__stdcall *fp_put)(BYTE);
typedef void (__stdcall *fp_flush)(void);
typedef void (__stdcall *fp_delay)(WORD);
WORD/BYTE/DWORD
类型在此处显示的单独.h
文件中定义:
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
现在,在我的Android代码中,我调用了一个名为InitRelayJava()的函数,我的应用程序的所有数据都存储在一个名为RelayAPIModel
的单独类中。我在其中创建了一个嵌套类来存储我的所有本机函数。我这样做是为了无论应用程序当前处于什么活动状态,我都能以相同的方式访问这些功能。
public class RelayAPIModel {
....
public static class NativeCalls {
static {
System.loadLibrary( "RelayAPI" );
}
public native static byte InitRelayJava();
public native static void FreeRelayJava();
public static void changeItJavaWrapper( short l ) {
mModelService.changeitJava( l );
}
public static void flushItJavaWrapper() {
mModelService.flushitJava();
}
public static void putItJavaWrapper( byte[] p ) {
mModelService.putitJava( p );
}
public static void delayItJavaWrapper( short wait ) {
mModelService.delayitJava( wait );
}
public static short getItJavaWrapper( short s ) {
return mModelService.getitJava( s );
}
}
}
*Wrapper
函数内部的调用将转到一个单独的类,我必须处理所有应用程序的蓝牙功能。我不认为这个问题需要这些。
这就是我的C代码中InitRelayJava的样子......
BYTE Java_my_eti_commander_RelayAPIModel_00024NativeCalls_InitRelayJava( JNIEnv *env, jobject obj ) {
myEnv = (env);
bluetoothClass = (*env)->GetObjectClass( env, obj );
myObject = obj;
changeID = (*myEnv)->GetMethodID( myEnv, myObject, "changeitJavaWrapper", "(S)V" );
getID = (*myEnv)->GetMethodID( myEnv, myObject, "getitJavaWrapper" , "(S)S" );
putID = (*myEnv)->GetMethodID( myEnv, myObject, "putitJavaWrapper" , "(B)V" );
flushID = (*myEnv)->GetMethodID( myEnv, myObject, "flushitJavaWrapper" , "()V" );
delayID = (*myEnv)->GetMethodID( myEnv, myObject, "delayitJavaWrapper" , "(S)V" );
...
}
这是我收到的LogCat ......
08-02 10:27:32.406: D/dalvikvm(28376): Trying to load lib /data/data/my.eti.commander/lib/libRelayAPI.so 0x40515430
08-02 10:27:32.406: D/dalvikvm(28376): Added shared lib /data/data/my.eti.commander/lib/libRelayAPI.so 0x40515430
08-02 10:27:32.406: D/dalvikvm(28376): No JNI_OnLoad found in /data/data/my.eti.commander/lib/libRelayAPI.so 0x40515430, skipping init
08-02 10:27:32.406: D/dalvikvm(28376): GetMethodID: method not found: Lmy/eti/commander/RelayAPIModel$NativeCalls;.changeitJavaWrapper:(S)V
08-02 10:27:32.413: D/dalvikvm(28376): GetMethodID: method not found: Lmy/eti/commander/RelayAPIModel$NativeCalls;.getitJavaWrapper:(S)S
08-02 10:27:32.413: E/dalvikvm(28376): Class lookup Ljava/lang/NoSuchMethodError; attempted while exception Ljava/lang/NoSuchMethodError; pending
答案 0 :(得分:1)
InitRelayJava
是一个静态方法 - 这意味着你的第二个参数(obj
)是一个类对象指针,而不是this
指针。所以摆脱以下几行:
bluetoothClass = (*env)->GetObjectClass( env, obj );
而是将obj
传递给GetMethodID(),如下所示:
changeID = (*myEnv)->GetMethodID( myEnv, obj, "changeitJavaWrapper", "(I)Z" );
编辑:此外,您的参数/返回类型签名是错误的。 Short与int不同,因此changeitJavaWrapper
的签名是“(S)Z”,getitJavaWrapper
的签名是“()I”,因为它不带参数并返回int。请小心点;它没有采用C的高级知识来获得正确的,只是一些自我检查。你的这个项目正在进入What have you tried?领域。
JNI类型代码here上的备忘单。
让我试着预测你的下一个问题 - 你不能称这些方法。当然你不能,从静态方法调用非静态方法是不可能的。您的Java回调都是非静态的,而本机方法是静态的。要么将它们设置为静态,要么使本机方法为非静态,然后插入GetObjectClass
。
EDIT2:所以你将Java方法改为静态而不告诉。现在,您需要调用(*env)->GetMethodID()
来获取方法ID,而不是(*env)->GetStaticMethodID()
。相同的参数。
答案 1 :(得分:0)
您的方法签名错误。使用javap -s classname
获取类的签名,例如:javap -s java.lang.String
。
您可以在本地JDK中找到javap
。