«this» не является допустимой ссылкой JNI в Android JNI

#java #android #android-ndk #java-native-interface

#java #Android #android-ndk #java-native-interface

Вопрос:

Я передаю текущую активность в собственный метод, используя собственный интерфейс Java на Android. Но я не делаю этого, используя JNI, подобные имена функций. Я регистрирую собственные функции вручную.

Это работает (именование JNI).

com_venkatesh_home.c

 JNIEXPORT void JNICALL Java_com_venkatesh_Home_doStuff(JNIEnv *env, jobject activity) {
    jclass Activity = (*env)->GetObjectClass (env, activity);
  

com.venkatesh.Home.java

 private native void doStuff();
static {
    System.loadLibrary("venkatesh");
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    doStuff();
 }
  

Но это не работает. (Ручная регистрация и передача активности в качестве объекта)

me.c

 static JavaVM *java_vm;

void do_stuff (jobject activity)
{
    JNIEnv *env;
    if ((*java_vm)->GetEnv(java_vm, (void **) amp;env, JNI_VERSION_1_6) != JNI_OK) {
        LOG_D("GetEnv failed");
        return -1;
    }

    jclass Activity = (*env)->GetObjectClass (env, activity);
}

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
    java_vm = vm;

    JNIEnv* env;
    if ((*vm)->GetEnv(vm, (void **) amp;env, JNI_VERSION_1_6) != JNI_OK) {
        LOG_D ("GetEnv failed.");
        return -1;
    }

    // Find the class calling native function
    jclass Home = (*env)->FindClass(env, "com/venkatesh/Home");
    if (Home == NULL) {
        LOG_D ("FindClass failed : No class found.");
        return -1;
    }

    // Register native method for getUsbPermission
    JNINativeMethod nm[1] = {
        { "doStuff", "(Landroid/app/Activity;)V", do_stuff}
    };

    if ((*env)->RegisterNatives(env, NativeUsb, nm , 1)) {
         LOG_D ("RegisterNatives Failed.");
         return -1;
    }

    return JNI_VERSION_1_6;
}
  

com.venkatesh.Home.java

 private native void doStuff(Activity activity);
static {
    System.loadLibrary("venkatesh");
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    doStuff(this);
 }
  

Ошибка

 JNI WARNING: 0xb89a7788 is not a valid JNI reference (GetObjectClass)
  

где 0xb89a7788 — это «это», полученное на стороне jni в качестве действия.

Теперь, как я понимаю, это представляет существующий объект. Эквивалентно self в python. Но затем я передаю объект на родную сторону, и, следовательно, он должен быть допустимой ссылкой. Почему ошибка недопустимой ссылки? Это не объект? Что не так?

Ответ №1:

Это происходит не из-за того, как регистрируется метод, а из-за сигнатуры вашего собственного метода. Я бы переписал этот метод следующим образом:

 void do_stuff (JNIEnv *env, jobject this, jobject activity)
{
    jclass Activity = (*env)->GetObjectClass (env, activity);
    // ...and whatever else you want...
}
  

Каждый метод JNI должен принимать a JNIEnv * в качестве своего первого параметра. (Обратите также внимание на отсутствие static env переменной — она не нужна). Кроме того, поскольку это не статический метод, первым параметром, переданным в метод, будет this and not activity .

Комментарии:

1. Большое спасибо. Это сработало. У меня были неполные знания. Итак, теперь я это понимаю. Для методов экземпляра вызываемая функция C неявно имеет 2 аргумента. JNIEnv * env — среда JNI и jobject obj — вызывающий объект. Далее следует любой аргумент, явно определенный в Java, начиная с третьего аргумента в C. Для статических методов в качестве аргумента передается только JNIEnv * . Явно определенные аргументы в Java поступают как аргументы, начиная со 2-го в C.