Red de conocimiento informático - Material del sitio web - Cómo implementar devoluciones de llamada en el hilo jni de Android

Cómo implementar devoluciones de llamada en el hilo jni de Android

La devolución de llamada JNI se refiere a llamar a una función java en código c/c. Cuando la función de devolución de llamada se ejecuta en el subproceso c/c, la devolución de llamada fallará.

Una de las soluciones en el sistema Android es:

Reemplazar la creación de todos los hilos en c/c mediante la función pthread_create con la función AndroidRuntime que crea hilos en la capa Java: :crearJavaThread.

Supongamos que hay una función c:

[cpp] ver copia simple

void *thread_entry(void *args)

{

while(1)

{

printf("hilo en ejecución...\n");

sleep(1); /p> p>

}

}

void init()

{

pthread_t hilo

pthread_create(amp; thread, NULL, thread_entry, (void *) NULL);

}

La función init() crea un hilo y debes llamarlo. clase java Prueba en el hilo Función de devolución de llamada Recibir:

[cpp] ver copia simple

public void Recibir(char buffer[], int length){

Cadena msg = new String(buffer );

msg = "recibido de devolución de llamada jni:" msg

Log.d("Prueba",

}

Primero defina el puntero de la función de devolución de llamada en c:

[cpp] ver copia simple

//test.h

# incluir lt; pthread.hgt ;

//tipo de función para recibir datos del

typedef nativo (*ReceiveCallback)(unsigned char *buf, int len ​​

);

/** Devolución de llamada para crear un hilo que pueda llamar al código del marco Java

* Esto debe usarse para crear cualquier hilo que informe eventos al marco. > */

typedef pthread_t (* CreateThreadCallback)(const char* nombre, void (*start)(void *), void* arg

typedef struct{

RecibirCallback recv_cb ;

CreateThreadCallback create_thread_cb;

}Callback

Modificar las funciones init y thread_entry en c:

[cpp] ver copia simple

//test.c

#include

lt;stdio.hgt;

#include lt;stdlib.hgt;

#include lt;pthread.hgt

#include lt;sys/wait; .hgt;

#include lt;unistd.hgt;

#include "test.h"

void *thread_entry(void *args)

{

char *str = "estoy feliz ahora";

Devolución de llamada cb = NULL

int len ​​

if(args != NULL){

cb = (Devolución de llamada *)args

}

len = strlen(str); p> p>

while(1)

{

printf("hilo en ejecución...\n"); método para java

if(cb != NULL amp; amp; cb-gt; recv_cb != NULL){

cb-gt; recv_cb((unsigned char*)str, len)

}

dormir(1

}

}

void init(Devolución de llamada); *cb )

{

pthread_t hilo

//pthread_create(amp; hilo, NULL, thread_entry, (void *)NULL

if(cb != NULL amp; cb-gt; create_thread_cb != NULL)

{

cb-gt; *)cb);

}

}

Luego implemente la función de devolución de llamada en jni y otras implementaciones:

[cpp] ver copia simple

//jni_test.c

#include lt; stdlib.hgt

#include malloc.hgt; >#include lt;jni.hgt;

#include lt;JNIHelp.hgt;

#include "android_runtime/AndroidRuntime.h"

#include " prueba.h"

#define RADIO_PROVIDER_CLASS_NA

ME "com/tonny/Test"

usando el espacio de nombres de Android

static jobject mCallbacksObj = NULL

static jmethodID Method_receive

static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* métodoName) {

if (env-gt;ExceptionCheck()) {

LOGE("Se produjo una excepción mediante la devolución de llamada '.", nombre_método);

LOGE_EX(env);

env-gt; ExceptionClear();

}

}

static void recibir_callback(unsigned char *buf, int len)

{

int i

JNIEnv* env = AndroidRuntime: :getJNIEnv();

jcharArray matriz = env-gt; NewCharArray(len);

jchar *pArray;

LOGE("receive_callback: error NewCharArray.");

return

}

pArray = (jchar*)calloc(; len, sizeof(jchar));

if(pArray == NULL){

LOGE("receive_callback: calloc error.");

}

//copiar el buffer a la matriz jchar

for(i = 0; i lt; len; i)

{

*(pArray i) = *(buf i);

}

//copiar el búfer a jcharArray

env-gt ; SetCharArrayRegion(array, 0, len, pArray);

//invocar el método de devolución de llamada de Java

env-gt; CallVoidMethod(mCallbacksObj, Method_receive, array, len

//liberar recurso

e

env-gt; DeleteLocalRef(array);

free(pArray);

pArray = NULL; , __FUNCTION__); ​​​​

}

static pthread_t create_thread_callback(const char* nombre, void (*start)(void *), void* arg)

{

return (pthread_t)AndroidRuntime::createJavaThread(nombre, inicio, arg

}

devolución de llamada estática mCallbacks = {

recibir_callback,

create_thread_callback

};

static void jni_class_init_native

(JNIEnv* env, jclass clazz)

{

método_receive = env-gt; GetMethodID(clazz, "Recibir", "([CI)V");

}

estático int jni_init

(JNIEnv *env, jobject obj)

{

if (!mCallbacksObj)

mCallbacksObj = env-gt; NewGlobalRef( obj);

return init(amp; mCallbacks);

}

static const JNINativeMethod gMethods[] = {

{ " class_init_native", "()V", (void *)jni_class_init_native },

{ "native_init", "()I", (void *)jni_init },

};

static int RegisterMethods(JNIEnv* env) {

const char* const kClassName = RADIO_PROVIDER_CLASS_NAME

jclass clazz; /* busca la clase */

clazz = env-gt; FindClass(kClassName

if (clazz == NULL) {

LOGE("No se puede encontrar la clase s/n", kClassName);

return -1;

}

/* registrar todos los métodos */

if (env-gt; RegisterNatives(clazz, gMethods, sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK)

{

LOGE("Métodos de registro fallidos para s/n", kClassName);

return

}

/* complete el resto del caché de ID */

return 0

}

jint JNI_OnLoad(JavaVM* vm, void* reservado) {

JNIEnv* env = NULL;

resultado jint = -1;

LOGI("Radio JNI_OnLoad"); *) amp; env, JNI_VERSION_1_4) != JNI_OK) {

LOGE("ERROR: GetEnv falló/n");

ir a fallar;

if(env == NULL){

ir a fallar

}

if (registerMethods(env) != 0) {

LOGE("ERROR: Error en el registro nativo de PlatformLibrary/n");

ir a fallar

}

/* éxito; -- devolver número de versión válido */

resultado = JNI_VERSION_1_4;

fallo:

devolver resultado

}

La configuración de la biblioteca compartida en el archivo Android.mk de jni es:

[cpp] ver copia simple

LOCAL_SHARED_LIBRARIES:= liblog libcutils libandroid_runtime libnativehelper

Finalmente implementar la clase Test en Java:

[java] ver pla

incopy

//com.tonny.Test.java

prueba de clase pública {

estática{

prueba {

System.loadLibrary("prueba");

class_init_native();

} catch(UnsatisfiedLinkError ule){

System.err.println( "ADVERTENCIA: ¡No se pudo cargar la biblioteca libtest.so!"

}

}

public int inicialize() {

); return nativo_radio_init();

}

public void Recibir(char buffer[], int length){

String msg = new String(buffer); /p>

msg = mensaje "recibido de devolución de llamada jni";

Log.d("Prueba", mensaje

}

protected); static nativo void class_init_native();

nativo protegido int native_init()

}