0

私のアプリケーションはネイティブ ライブラリを呼び出し、次にネイティブ ライブラリ内で Java コードを呼び出します。ネイティブライブラリへの呼び出しは正しく機能していますが(私はかなり確信しています)、CファイルからJava関数を呼び出そうとしたときにJava関数が見つからないことを教えてくれません。

アプリケーションはクラッシュすることさえありません。予期せず終了したことを知らせるポップアップはありません。黒い画面が点滅するだけで、何も起こりません。

私が再現しようとしているコードは、もともと Palm Pilot 用に C で作成されたもので、Android デバイスに転送されています。これは、複製しようとしている CI の元の呼び出しです...

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ファイルで型定義されています。

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、アプリケーションのすべての Bluetooth 機能を処理する必要がある別のクラスに送られます。この問題にはそれらが必要だとは思いません。

これは私の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
4

2 に答える 2

1

InitRelayJavaは静的メソッドです。つまり、2番目のパラメーター(obj)は、ポインターではなく、クラスオブジェクトポインターthisです。したがって、次の行を削除します。

bluetoothClass = (*env)->GetObjectClass( env, obj );

obj代わりに、次のようにGetMethodID()に渡します。

changeID = (*myEnv)->GetMethodID( myEnv, obj, "changeitJavaWrapper", "(I)Z"  ); 

編集:また、パラメータ/リターン型の署名が間違っています。Shortはintと同じではないため、のシグネチャchangeitJavaWrapperは "(S)Z"であり、forgetitJavaWrapperは "()I"です。これは、パラメータを受け取らず、intを返すためです。もっと注意してください。それらを正しくするためにCの高度な知識は必要ありません。自己チェックするだけです。あなたのこのプロジェクトは、何を試しましたか?地域。

JNIタイプコードのチートシートはこちら

次の質問を試してみてください。これらのメソッドを呼び出すことはできません。もちろんできません。静的メソッドから非静的メソッドを呼び出すことはできません。Javaコールバックはすべて非静的ですが、ネイティブメソッドは静的です。それらを静的にするか、ネイティブメソッドを非静的にしてGetObjectClassバックを挿入します。

EDIT2:それであなたはあなたのJavaメソッドを言わずに静的に変更しました。代わりに、メソッドIDを取得する(*env)->GetMethodID()ために呼び出す必要があります。(*env)->GetStaticMethodID()同じパラメータ。

于 2012-08-01T18:24:56.100 に答える
0

メソッドの署名が間違っています。javap -s classnameクラスのシグネチャを取得するために使用します。例: javap -s java.lang.String. javapローカルの JDK で見つけることができます。

于 2012-08-02T13:21:03.640 に答える