Подтвердить что ты не робот

Как создать объект с JNI?

Мне нужно реализовать некоторые функции в Android-приложении, используя NDK и, следовательно, JNI.

Вот код C, с моими проблемами, который я написал:

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

jobject
Java_com_example_ndktest_NDKTest_ImageRef(JNIEnv* env, jobject obj, jint width, jint height, jbyteArray myArray)
{
    jint i;
    jobject object;
    jmethodID constructor;
    jobject cls;
    cls = (*env)->FindClass(env, "com/example/ndktest/NDKTest/Point");

//what should put as the second parameter? Is my try correct, according to what
//you can find in .java file? I used this documentation: http://download.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#wp16027

    constructor = (*env)->GetMethodID(env, cls, "<init>", "void(V)");
//http://download.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#wp16660
//Again, is the last parameter ok?

    object = (*env)->NewObject(env, cls, constructor, 5, 6);
//I want to assign "5" and "6" to point.x and point.y respectively.
    return object;
}    

Мои проблемы более или менее объясняются внутри кода. Возможно, также: является ли возвращаемый тип функции (jobject) нормально?

Теперь NDKTest.java:

package com.example.ndktest;

import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;

public class NDKTest extends Activity {
    /** Called when the activity is first created. */
    public native Point ImageRef(int width, int height, byte[] myArray);
    public class Point
    {

        Point(int myx, int myy)
        {
            x = myx;
            y = myy;
        }

        int x;
        int y;
    }

    @Override
    public void onCreate(Bundle savedInstanceState)
    {

         super.onCreate(savedInstanceState);
         TextView tv = new TextView(this);
         byte[] anArray = new byte[3];
         for (byte i = 0; i < 3; i++)
             anArray[i] = i;
         Point point = ImageRef(2, 3, anArray);
         tv.setText(String.valueOf(point.x));
            setContentView(tv);     
    }



    static
    {
       System.loadLibrary("test");
    }
}

Когда я пытаюсь запустить код, он не работает.

4b9b3361

Ответ 1

Так как Point является внутренним классом, способ получить его будет

jclass cls = (*env)->FindClass(env, "com/example/ndktest/NDKTest$Point");

Конгресс $ для внутренних классов на самом деле не задокументирован в авторитетных спецификациях, но укоренился в таком рабочем коде, который вряд ли изменится. Тем не менее, он будет чувствовать себя более уверенно, если вы ограничили свой JNI-код работой с классами верхнего уровня.

Вам нужен конструктор, который принимает два ints в качестве аргументов. Подпись для этого (II)V, поэтому:

constructor = (*env)->GetMethodID(env, cls, "<init>", "(II)V");

В следующий раз включите некоторую обработку ошибок в свой код, чтобы у вас была подсказка, какая часть ее не работает!

Ответ 2

Спецификация верна, но в этом случае она немного вводит в заблуждение. GetMethodID требуется имя метода и подпись метода. В спецификации указано:

Чтобы получить идентификатор метода конструктора, поставьте <init> как имя метода и void (V) в качестве возвращаемого типа.

Обратите внимание, что он говорит тип возврата, а не подпись. Хотя void(V) внешне внешне похож на подпись, спецификация сообщает вам, что подпись должна указывать тип возврата void (т.е. V).

Правильной сигнатурой для конструктора без аргументов является ()V. Если у конструктора есть аргументы, они должны быть описаны между круглыми скобками, как отмечали другие комментаторы.

Ответ 3

Некоторые проблемы с вашим кодом.

Во-первых, почему вы создаете свой собственный класс Point вместо использования предоставленного библиотекой android.graphics.Point?

Во-вторых, спецификация класса для вложенных классов отличается - это будет "com/example/ndktest/NDKTest $Point". Вложенность классов отличается от пакетов.

В-третьих, я не думаю, что JNI позволяет создавать экземпляры нестатических вложенных классов. Вам нужно передать указатель объекта-указателя класса "this при создании объекта - нет такого аргумента.

Наконец, хотя я видел руководство использовать "void (V)" как подпись метода конструктора, но это не соответствует остальным сигнатурам методов; обычно, метод с двумя параметрами int и типом возврата void будет "(II) V".

В качестве побочного примечания я счел гораздо более чистым передавать примитивные типы и массивы примитивов, набранных с NDK на Java. Создание/доступ к объектам беспорядочно и сложно отлаживать.

Ответ 4

В JNI вы всегда можете использовать инструмент javap для поиска сигнатур методов. Просто запустите javap -s com.example.ndktest.NDKTest и скопируйте сигнатуры метода из вывода.

Ответ 5

Три шага должны создать объект Point с JNI:

jobject
Java_com_example_ndktest_NDKTest_ImageRef(JNIEnv* env, jobject obj, jint width, jint height, jbyteArray myArray)
{
    ...
    jclass cls = (*env)->FindClass(env, "com/example/ndktest/NDKTest$Point");
    jmethodID constructor = (*env)->GetMethodID(env, cls, "<init>", "void(V)");
    jobject object = (*env)->NewObject(env, cls, constructor, obj, 5, 6);
    ...
}