Android'de c ++ 'dan bir java yöntemini çağırma


91

Java yerel yöntemi çağırırken C ++ 'dan basit bir Java yöntem çağrısı almaya çalışıyorum. İşte Java kodu:

public class MainActivity extends Activity {
    private static String LIB_NAME = "name";

    static {
        System.loadLibrary(LIB_NAME);
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = (TextView) findViewById(R.id.textview);
        tv.setText(this.getJniString());
    }

    public void messageMe(String text) {
        System.out.println(text);
    }

    public native String getJniString();
}

Java'dan yerele yöntem çağrısı messageMesürecinde yerel koddan yöntemi çağırmaya çalışıyorum getJniString*.

native.cpp:

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

jstring Java_the_package_MainActivity_getJniString( JNIEnv* env, jobject obj, jint depth ){

//    JavaVM *vm;
//    JNIEnv *env;
//    JavaVMInitArgs vm_args;
//    vm_args.version = JNI_VERSION_1_2;
//    vm_args.nOptions = 0;
//    vm_args.ignoreUnrecognized = 1;
//
//    // Construct a VM
//    jint res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);

    // Construct a String
    jstring jstr = env->NewStringUTF("This string comes from JNI");
    // First get the class that contains the method you need to call
    jclass clazz = env->FindClass("the/package/MainActivity");
    // Get the method that you want to call
    jmethodID messageMe = env->GetMethodID(clazz, "messageMe", "(Ljava/lang/String;)V");
    // Call the method on the object
    jobject result = env->CallObjectMethod(jstr, messageMe);
    // Get a C-style string
    const char* str = env->GetStringUTFChars((jstring) result, NULL);
    printf("%s\n", str);
        // Clean up
    env->ReleaseStringUTFChars(jstr, str);

//    // Shutdown the VM.
//    vm->DestroyJavaVM();

    return env->NewStringUTF("Hello from JNI!");
}

Temiz derleme uygulaması bir sonraki mesajla durduktan sonra:

ERROR/AndroidRuntime(742): FATAL EXCEPTION: main
        java.lang.NoSuchMethodError: messageMe
        at *.android.t3d.MainActivity.getJniString(Native Method)
        at *.android.t3d.MainActivity.onCreate(MainActivity.java:22)

Görünüşe göre bu, yöntem adının yanlış olduğu anlamına geliyor, ancak bana iyi görünüyor.


21
Hem sorunuzun hem de çözümün okunmasını kolaylaştırmak ve dolayısıyla topluluk için daha yararlı hale getirmek için lütfen çözümünüzü sıradan bir yanıt olarak gönderin. Ayrıca, yanıtlarını tamamlamak için zaten yanıtlamış olan diğer kişilerle işbirliği yapabilirsiniz.
misiu_mp

@Denys: Kodunuzu takip ettim ama şu hatayı alıyorum: java.lang.UnsatisfiedLinkError: getJniString. Bu hatayı düzeltmeme yardım edebilir misin?
Huy Tower

@AlexTran, uzun zaman önceydi, ancak hataya bakılırsa muhtemelen yanlış yazdığınız veya getJniStringyöntemi java veya c'de bağlamadınız . C kodunu java'ya muhtemelen sistem içe aktararak doğru şekilde bağladığınızdan emin olun (srsly şu anda tüm bunları hatırlamıyorum: P)
Denys S.

1
Bu, c'den java yöntemini nasıl çağırıyor? Açıkçası Java'nın onCreateyerel
John

'->' temel işleneninin ortam (env) değişkeniyle çalıştırıldığında işaretçi olmayan 'JNIEnv türüne sahip olduğunu alıyorum . Ayrıca, JNI'den Java katmanına geri arama gibi env * değişkeni olmadan yapmak istersek ne olur? Herhangi bir öneri!
CoDe

Yanıtlar:


45

Bir nesne yöntemi ise, nesneyi şunlara iletmeniz gerekir CallObjectMethod:

jobject result = env->CallObjectMethod(obj, messageMe, jstr);

Yaptığın şeye eşdeğerdi jstr.messageMe().

Sizin yönteminiz geçersiz bir yöntem olduğu için şunu aramalısınız:

env->CallVoidMethod(obj, messageMe, jstr);

Bir sonuç döndürmek isterseniz, JNI imzanızı ( dönüş türü ()Vyöntemi anlamına gelir void) ve ayrıca Java kodunuzdaki dönüş türünü değiştirmeniz gerekir.


Lütfen, bunu nasıl yapacağım konusunda bana rehberlik edin, çünkü
PS'im

Önerdiğin şeyle aynı sonucu alıyorum.
Denys S.

1
aslında her biri farklı bir dönüş türüne sahip bir CallVoidMethod, CallObjectMethod, vb. vardır. MessageMe yönteminiz (Ljava / lang / String;) V olduğundan, CallVoidMethod'u kullanmanız gerekir.
Matthew Willis

2
Muhtemelen aldığınız hatanın, Java yerel yönteminizin (Java kodunuzda) büyük olasılıkla geçersiz dönüş türü olmadığını ve bu nedenle GetMethodID tarafından bulunmadığını gösterdiğini unutmayın
Matthew Willis

10

Denys S. tarafından soru gönderisinde yayınlanan çözüm :

Bunu c'den c ++ 'ya dönüştürme (temelde envdeğişken şeyler) ile oldukça karıştırdım , ancak C ++ için aşağıdaki kodla çalıştırdım:

#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);
}

Ve java yöntemleri için sonraki kod:

    public class MainActivity extends Activity {
    private static String LIB_NAME = "thelib";

    static {
        System.loadLibrary(LIB_NAME);
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView tv = (TextView) findViewById(R.id.textview);
        tv.setText(this.getJniString());
    }

    // please, let me live even though I used this dark programming technique
    public String messageMe(String text) {
        System.out.println(text);
        return text;
    }

    public native String getJniString();
}

Do nativeyöntemler statik olmak zorunda?
IgorGanapolsky
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.