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)
{ p >
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()
}