Resumen de uso de Android JNI

En este artículo, omitimos el mecanismo subyacente de JNI, es mejor que el lector lo considere como el pegamento entre el código nativo y el código Java.

En términos sencillos, JNI es una tecnología a través de la cual se pueden lograr los dos puntos siguientes:
· Una función en un programa Java puede llamar a una función escrita en lenguaje nativo Nativo generalmente se refiere a una función escrita en C / C ++.
· La función en el programa nativo puede llamar a la función de la capa de Java, es decir, la función de Java se puede llamar en el programa C / C ++.

Pasos para llamar a la biblioteca C / C ++ en Android:

  • El primer paso: introduzca el nombre de la biblioteca de código C a través de System.loadLibrary.
  • Paso 2: Escriba el código C / C ++ en natice-lib.cpp en el directorio cpp.
  • Paso 2: Llame al método de implementación correspondiente en el archivo C / C ++.

API de JNI / NDK 的

         Para acceder al código del lado de Java en el código nativo de C / C ++, una aplicación común es obtener los atributos de la clase y llamar al método de la clase. Para expresar los atributos y métodos en C / C ++, JNI define jfieldID en el archivo de encabezado jni.h, el tipo jmethodID representa los atributos y métodos en el lado de Java, respectivamente. Al acceder o configurar una propiedad de Java, primero debe obtener el jfeldID que representa la propiedad de Java en el código local y luego realizar la operación de propiedad de Java en el código nativo. De manera similar, cuando necesite llamar a un método en el lado de Java, También es necesario obtener el representante del método El jmethodID se puede utilizar para llamadas al método Java. A continuación, intente llamar a un método en Java en nativo.

Tipo de JNIEnv y tipo de trabajo

JNIEnv * env y la instancia de jobjet, presentan brevemente el rol de estos dos tipos.

Tipo de JNIEnv

El tipo JNIEnv en realidad representa el entorno Java, y el código en el lado de Java se puede manipular a través del puntero JNIEnv *. Por ejemplo, podemos usar JNIEnv para crear objetos en clases Java, llamar a métodos de objetos Java y obtener propiedades en objetos Java.

Hay muchas funciones disponibles en la clase JNIEnv , como se muestra a continuación:

  • NewObject: crea un objeto en la clase Java.
  • NewString: crea un objeto String en la clase Java.
  • NewArray: crea un objeto de matriz de tipo Type.
  • GetField: Obtiene el campo de tipo Type.
  • SetField: establece el valor de un campo cuyo tipo es Type.
  • GetStaticField: Obtiene el campo estático de tipo Type.
  • SetStaticField: establece el valor del campo estático de tipo Type.
  • CallMethod: llama al método cuyo tipo de retorno es Type.
  • CallStaticMethod: llama al método estático cuyo tipo de valor de retorno es Type.
    Por supuesto, además de estas funciones de uso común, hay más funciones que se pueden usar, que se pueden ver en el archivo jni.h, o consultar https://docs.oracle.com/javase/6/docs/ technotes / guides /jni/spec/jniTOC.html enlace para consultar métodos relacionados, lo anterior es muy claro.

Bien, después de hablar sobre JNIEnv, hablemos del segundo proyecto.

tipo de trabajo

Jobject se puede considerar como una referencia a una instancia de clase en java. Por supuesto, diferentes situaciones tienen diferentes significados. Si el método nativo no es estático, obj representa la instancia de clase del método nativo.

Si el método nativo es estático, obj representa la instancia de objeto de clase de la clase de método nativo (el método estático no requiere una instancia de clase, por lo que representa el objeto de clase de esta clase).

La sintaxis para llamar a métodos en Java en lenguaje C es similar a la reflexión en Java. El mapeo de objetos en Java está representado por jobject en lenguaje C.

Para dar un ejemplo simple: creamos un método estático testStaticCallMethod y un método no estático testCallMethod en TestJNIBean. ¿Cómo escribimos en el archivo cpp?

TestJNIBean的代码:

 public class TestJNIBean{
    public static final String LOGO = "learn android with aserbao";
    static {
        System.loadLibrary("native-lib");
     }
    public native String testCallMethod();  //非静态
 
    public static native String testStaticCallMethod();//静态
 
    public  String describe(){
        return LOGO + "非静态方法";
    }

    public static String staticDescribe(){
        return LOGO + "静态方法";
    }
}
cpp文件中实现:

 extern "C"
 JNIEXPORT jstring JNICALL
 Java_com_example_androidndk_TestJNIBean_testCallMethod(JNIEnv *env, jobject instance) {
    jclass  a_class = env->GetObjectClass(instance);                                   //因为是非静态的,所以要通过GetObjectClass获取对象
    jmethodID  a_method = env->GetMethodID(a_class,"describe","()Ljava/lang/String;");// 通过GetMethod方法获取方法的methodId.
    jobject jobj = env->AllocObject(a_class);                                         // 对jclass进行实例,相当于java中的new
    jstring pring= (jstring)(env)->CallObjectMethod(jobj,a_method);                 // 类调用类中的方法
    char *print=(char*)(env)->GetStringUTFChars(pring,0);                           // 转换格式输出。 
    return env->NewStringUTF(print);
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_androidndk_TestJNIBean_testStaticCallMethod(JNIEnv *env, jclass type) {
    jmethodID  a_method = env->GetMethodID(type,"describe","()Ljava/lang/String;"); // 通过GetMethod方法获取方法的methodId.
    jobject jobj = env->AllocObject(type);                                          // 对jclass进行实例,相当于java中的new
    jstring pring= (jstring)(env)->CallObjectMethod(jobj,a_method);                 // 类调用类中的方法
    char *print=(char*)(env)->GetStringUTFChars(pring,0);                           // 转换格式输出。
    return env->NewStringUTF(print);
}

La mayor diferencia entre los dos métodos anteriores es que el método estático se pasará directamente a la clase j, por lo que podemos omitir el paso de obtener la clase j, y el método no estático pasa a la clase actual. 

GetFieldID是得到java类中的参数ID,GetMethodID得到java类中方法的ID,它们只能调用类中声明为 public的参数或方法。使用如下:

jfieldID topicFieldId = env->GetFieldID(objectClass,"name", "Ljava/lang/String;");
jmethodID getcName=env->GetMethodID(objectClass,"getcatName","()Ljava/lang/String;");

El primer parámetro es un objeto de clase Java. El segundo parámetro es el parámetro (o nombre del método) y el tercer parámetro es la firma del parámetro (o método). El tercer parámetro se obtiene mediante el siguiente método.

Llamar a código Java en C / C ++

Cómo obtener clases en Java y generar objetos

Hay varios métodos en la clase JNIEnv para obtener las clases en java:

  • jclass FindClass (const char * name) Encuentra una clase de acuerdo con el nombre de la clase, el nombre completo de la clase
A lo que debemos prestar atención es a que el nombre del parámetro del método FindClass es la ruta completa de una determinada clase. Por ejemplo, si queremos llamar al método getTime de la clase Date en Java, podemos hacer esto:

 

 extern "C"
 JNIEXPORT jlong JNICALL
 Java_com_example_androidndk_TestJNIBean_testNewJavaDate(JNIEnv *env, jobject instance) {
     jclass  class_date = env->FindClass("java/util/Date");//注意这里路径要换成/,不然会报illegal class name
     jmethodID  a_method = env->GetMethodID(class_date,"<init>","()V");
     jobject  a_date_obj = env->NewObject(class_date,a_method);
     jmethodID  date_get_time = env->GetMethodID(class_date,"getTime","()J");
     jlong get_time = env->CallLongMethod(a_date_obj,date_get_time);
     return get_time;
}
  • jclass GetObjectClass (jobject obj) Según un objeto, obtiene la clase del objeto

¿Cómo llamar a métodos Java en C / C ++?

En el entorno JNIEnv, tenemos los siguientes dos métodos para obtener métodos y atributos:

  • GetMethodID: Obtiene el ID de un método no estático;
  • GetStaticMethodID: obtenga el ID del método estático;
    para obtener el jmethodID correspondiente.

El método GetMethodID es el siguiente:

1  jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)

La descripción del parámetro del método:

  • clazz: El objeto de clase del objeto de clase del que depende este método.
  • name: el nombre de este campo.
  • sign: La firma de este campo (cada variable y cada método tiene una firma correspondiente).

Modificar variables de Java en C / C ++

La idea de modificar las variables correspondientes en Java es realmente muy simple.

  • Encuentra el objeto de clase correspondiente.
  • Encuentre los atributos en la clase que necesitan ser modificados
  • Reasignar propiedades en la clase
代码如下:

 public class TestJNIBean{
     static {
         System.loadLibrary("native-lib");
     }
      public int modelNumber = 1;
     /**
      * 修改modelNumber属性
      */
     public native void testChangeField();
}

/*
 * 修改属性
 */
extern "C"
JNIEXPORT void JNICALL
Java_com_example_androidndk_TestJNIBean_testChangeField(JNIEnv *env, jobject instance) {
    jclass  a_class = env->GetObjectClass(instance);                // 获取当前对象的类
    jfieldID  a_field = env->GetFieldID(a_class,"modelNumber","I"); // 提取类中的属性
    env->SetIntField(instance,a_field,100);                         // 重新给属性赋值
}
调用testChangeField()方法后,TestJNIBean中的modelNumber将会修改为100。

Manipular matrices de Java en C / C ++

jType * GetArrayElements ((Array array, jboolean * isCopy)): este tipo de método puede convertir la matriz de tipos básicos de Java en una matriz en C / C ++ . Cuando isCopy es verdadero, significa que los datos se copiarán y el puntero de los datos devueltos es el puntero de la copia. Si es falso, no se copiará y el puntero de los datos de Java se utilizará directamente. No aplicable isCopy puede pasar NULL o 0.

La diferencia entre newObject y AllocObject

(1) AllocObject Esto es para asignar espacio de memoria para el objeto, y no hay inicialización de variable ni llamada al método de construcción.

newObject inicializa variables y llama al método de construcción especificado

(2) Obtenga la firma del método usando el comando Javap

例如 : javap -classpath F: \ JNI \ app \ build \ intermediates \ javac \ debug \ compileDebugJavaWithJavac \ classes -s com.example.jni.CTransferJava

(3) GetMethodID para obtener el constructor usando <init> en su lugar

Enlace de suplemento de conocimientos: https://www.freesion.com/article/3964761069/

Supongo que te gusta

Origin blog.csdn.net/wzhrsh/article/details/113932878
Recomendado
Clasificación