20

Android アプリケーションを構築しているプロジェクトの C++ 側に取り組んでいます。Java アプリケーションに (JNI 経由で) 渡す必要がある情報が (文字列および文字列配列経由で) いくつかあります。私はこれまでにこれを行ったことがなく、逆方向で作業している人々は C++ の経験がなく、実際には役に立たないことを認めています。

次のコードを見つけました(ここから)

 #include <jni.h>  
    #include "ArrayHandler.h"  

    JNIEXPORT jobjectArray JNICALL Java_ArrayHandler_returnArray (JNIEnv *env, jobject jobj){        
      jobjectArray ret;  
      int i;  
      char *message[5]= {"first","second","third","fourth","fifth"};  
      ret= (jobjectArray)env->NewObjectArray(5,env->FindClass("java/lang/String"),env->NewStringUTF(""));  

      for(i=0;i<5;i++) {  
        env->SetObjectArrayElement(ret,i,env->NewStringUTF(message[i]));  
      }  
      return(ret);  
    }  

しかし、これは私には意味がありません。ほとんどの場合、これをプログラムの C++ 側に組み込む方法がわかりません。これがどのように機能するかを正確に理解できていません。コードは行の実行時にメッセージを送信していますreturn(ret);か? または for ループ内の行の実行中ですか?

理想的には、新しい関数を組み込む必要がないように、関数の最後ではなく、文字列/文字列配列を「ライブ」で送信したいと考えています。

私が見つけたコードは、私が望むものに対して機能しますか? 私が探しているものは可能ですか?もしそうなら、どうすればいいですか?

編集/更新: JNIと用語を調べるのに1日を費やしたので、ここと@jogabonitoの回答/返信へのコメントの両方で、私が達成しようとしていることを正しく伝えることができなかったと思います.

そうは言っても。私が取り組んでいるコードは、Android アプリケーションが更新をポーリングしないように、メッセージとプレゼンスの更新を (JNI 経由で) Android Java アプリケーションにプッシュする必要がある IM クライアント用です。Javaコードが情報を要求するために呼び出す関数をセットアップする方法を学ぶことができました。ただし、新しいメッセージまたはプレゼンス情報 (jabber スタンザ文字列) が入ってきたときに Java コードにプッシュする方法がわかりません。 Java コード (env、class、methodid など) から情報を取得する必要があります。

関数を呼び出すJavaコードではなく、私のC ++コードである場合、これがどのように可能になるのか、私には意味がありません。説明/ヘルプをいただければ幸いです。

#include <string.h>
#include <stdio.h>
#include <jni.h>

jstring Java_the_package_MainActivity_getJniString( JNIEnv* env, jobject obj){

    jstring jstr = (*env)->NewStringUTF(env, "This comes from jni.");
    jclass clazz = (*env)->FindClass(env, "com/inceptix/android/t3d/MainActivity");
    jmethodID messageMe = (*env)->GetMethodID(env, clazz, "messageMe", "(Ljava/lang/String;)Ljava/lang/String;");
    jobject result = (*env)->CallObjectMethod(env, obj, messageMe, jstr);

    const char* str = (*env)->GetStringUTFChars(env,(jstring) result, NULL); // should be released but what a heck, it's a tutorial :)
    printf("%s\n", str);

    return (*env)->NewStringUTF(env, str);
}
4

4 に答える 4

4

あなたが共有した関数では、あなたのC++コードでオブジェクト配列を作成していますNewObjectArray. 次に、 for ループで を使用して文字列を作成し、NewStringUTFを使用して配列のインデックスに格納しますSetObjectArrayElement。これまで、オブジェクト配列は C++ コードのみが認識しており、Java コードは認識していません。あなたがそれを返すときだけ、あなたのJavaアプリはそれにアクセスできます。
文字列を C++ から Java に送信する方法はいくつか考えられますが、意図したとおりではない可能性があります。

  1. String 配列をネイティブ関数に渡します。ネイティブ コードでは、 を使用して各要素にアクセスし、 を使用GetObjectArrayElementして更新できますSetObjectArrayElement。あなたが望まないと私が推測する関数を呼び出さなければならないので、これはおそらく無意味です。

  2. Java コードでフィールドとして定義された文字列が既にある場合は、ネイティブから と を使用してアクセスし、 を使用してGetFieldID更新GetObjectFieldできますSetObjectField。ただし、フィールドが更新されたことをJavaコードに通知する方法がわかりません(必要な場合)

編集
あなたが書いた更新された関数は、Javaレイヤーから呼び出されることを意図しています。これの手がかりは、関数の名前ですJava_the_package_MainActivity_getJniStringenvネイティブ コンテキストから Java コードを呼び出すには、Java からおよびへの参照が必要ですobjHow do I load my own Java class in C on Android? をご覧ください。これを取得するためのアプローチ。おそらく、JNI でグローバル参照を使用する方法も調べる必要があります。

于 2012-07-24T11:51:07.597 に答える
2

c-string を jstring に変換して返すことができます。例は次のようになります。

JNIEXPORT jstring JNICALL Java_Class_Method(jstring data) 
{

    // jstring to char *
    const char *cStr = (*env)->GetStringUTFChars(env, data, NULL);

    // convert char * to jstring and return it
    return ((*env)->NewStringUTF(env, cStr));
}
于 2014-03-07T22:44:37.657 に答える
1

通常、JNIでは、呼び出しはJVMからCコードに送られます。通常のパラダイムは次のとおりです。

  1. Javaプログラマーは、 (実装なし)classとして宣言されたいくつかのメソッドを使用してJavaを作成します。native
  2. Javaプログラマーはでコンパイルしclassますjavac
  3. Javaプログラマーjavahはコンパイルされた.classファイルに対して実行します。これにより.hヘッダーファイルが生成されます
  4. Cプログラマー#includeが新しいヘッダーファイルを作成し、インターフェイスを実装します

これを逆方向(Javaとの接触を開始するCコード)で行うことについて私が見た唯一の例は、Cコードに実際にJVMを作成させることを含みます。

コードサンプルに関する質問に答えるために、作成中のJava文字列は、論理的には、コード実行の最後にreturnステートメントとともに返されます。これは、論理的には、その実行スレッドのプログラムフローがJVMに返されるときです。

于 2012-07-23T22:38:29.780 に答える