Android JNI开发(10)--实例

本文介绍了一个具体的Java应用与本地代码通过JNI进行交互的例子。详细展示了如何从Java调用本地方法,以及本地方法如何反过来调用Java方法的过程,包括多线程环境下方法的调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写那么多不如来点代码实在!!!
Java代码:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void callNative(View view){
        Toast.makeText(getApplicationContext(),helloMethod("hello native"),Toast.LENGTH_SHORT).show();
    }

    public void callJava(View view){
        nativeCallJava();
    }

    public void CallJavaInThread(View view){
        nativeCallJavaInThread();
    }

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

    public native String helloMethod(String input);
    public native void nativeCallJava();
    public native void nativeCallJavaInThread();

    public static void nativeCall(String message){
        Log.e("MainActivity","nativeCall : "+message);
    }

    public void nativeCall_nonStatic(String message){
        Log.e("MainActivity","nativeCall_nonStatic : "+message);
    }

}

onload.h

#ifndef JNIC2JAVA_ONLOAD_H
#define JNIC2JAVA_ONLOAD_H

#endif //JNIC2JAVA_ONLOAD_H
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <assert.h>
#include <android/log.h>
#include "test.h"
//extern供其他文件使用,作为一个全局变量,这时候的值会同步
JavaVM *savedVm;
jclass clazz_global;//用于在多线程中回调java中的方法。
jobject object_global;
//注意static定义的全局变量的不同

//static JavaVM *savedVm;
//static jclass clazz_global;//static定义的变量,不能在其他文件中访问。可以再同一文件中多线程访问
//static jobject object_global;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm,void *reserved);
jint register_method(JNIEnv *env);
jint registerNativeMethods(JNIEnv* env, const char *class_name, JNINativeMethod *methods, int num_methods);
JNIEXPORT jstring JNICALL  helloMethod(JNIEnv *env, jobject thiz,jstring input);
JNIEXPORT void JNICALL nativeCallJava(JNIEnv *env, jobject thiz);
JNIEnv *getEnv();
JNIEXPORT void JNICALL nativeCallJavaInThread(JNIEnv *env, jobject thiz);
void* callJava_thread_func(void* p);

onload.cpp

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <assert.h>
#include <android/log.h>
#include "onload.h"
#include<pthread.h>


#define TAG "myDemo-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型

JavaVM *savedVm;
jclass clazz_global;//用于在多线程中回调java中的方法。
jobject object_global;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm,void *reserved){

    LOGE("JNI_Onload in 1");
    JNIEnv *env = NULL;
    int result = -1;

    if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
    LOGE("JNI_Onload in 2");
        return JNI_ERR;
    }
    result = register_method(env);
    savedVm = vm;
    LOGE("JNI_Onload in 3 , result is %d", result);
    return JNI_VERSION_1_6;
}

JNINativeMethod methods[] = {
    {"helloMethod","(Ljava/lang/String;)Ljava/lang/String;",(void*)helloMethod},
    {"nativeCallJava","()V",(void*)nativeCallJava},
    {"nativeCallJavaInThread","()V",(void*)nativeCallJavaInThread}
};

jint register_method(JNIEnv *env){
    LOGE("register_method in 1");
    int result = registerNativeMethods(env,"com/xxxx/jni/MainActivity",methods, sizeof(methods) / sizeof(methods[0]));
    LOGE("register_method in 2,result is %d ",result);
    return result;
}

jint registerNativeMethods(JNIEnv* env, const char *class_name, JNINativeMethod *methods, int num_methods) {
    int result = 0;
    LOGE("registerNativeMethods in 1");
    jclass clazz = env->FindClass(class_name);
    clazz_global = (jclass)env->NewGlobalRef(clazz);
    LOGE("registerNativeMethods in 2");
    if(clazz == NULL){
    LOGE("registerNativeMethods in 3");
        return JNI_FALSE;
    }
    LOGE("registerNativeMethods in 4");
    result = env->RegisterNatives(clazz, methods, num_methods);
    LOGE("registerNativeMethods in 5");
    if(result < 0){
    LOGE("registerNativeMethods in 6");
        return JNI_FALSE;
    }
    LOGE("registerNativeMethods in 7 ,result is %d",result);
    return result;
}
//Java调用native方法
JNIEXPORT jstring JNICALL  helloMethod(JNIEnv *env, jobject thiz,jstring input){
    LOGE("helloMethod in 1");
    const char *result_char = env->GetStringUTFChars(input,JNI_FALSE);
    jstring result = env->NewStringUTF(result_char);
    return result;
}
//native方法将调用Java方法
JNIEXPORT void JNICALL nativeCallJava(JNIEnv *env, jobject thiz){
    object_global = (jobject)env->NewGlobalRef(thiz);
    LOGE("nativeCallJava in 1");
    env = getEnv();
    LOGE("nativeCallJava in 2");
    jclass clazz = env->FindClass("com/xxxx/jni/MainActivity");
    LOGE("nativeCallJava in 3");
    jmethodID method1 = env->GetStaticMethodID(clazz,"nativeCall","(Ljava/lang/String;)V");
    LOGE("nativeCallJava in 4");
    jstring result = env->NewStringUTF("aaaaaaaaa");
    env->CallStaticVoidMethod (clazz, method1,result);
    LOGE("nativeCallJava in 5");


    jmethodID method2 = env->GetMethodID(clazz,"nativeCall_nonStatic","(Ljava/lang/String;)V");
    LOGE("nativeCallJava in 6");
    env->CallVoidMethod (thiz, method2,result);
}

JNIEXPORT void JNICALL nativeCallJavaInThread(JNIEnv *env, jobject thiz){

    pthread_t native_thread;
    pthread_create(&native_thread, NULL, callJava_thread_func,NULL);
//在另一个文件中的线程
    pthread_create(&native_thread, NULL, testcallJava_thread_func,NULL);

//   testCallJavaInThread();
}
//在多线程中调用java的方法
void* callJava_thread_func(void* p){
    LOGE("callJava_thread_func in 1");
    JNIEnv *env ;
    if (savedVm->AttachCurrentThread(&env, 0) != 0)
    {
        LOGE("Failed to attach current thread");
        return 0;
    }
    LOGE("callJava_thread_func in 2");
//    jclass clazz = env->FindClass("com/xxxx/jni/MainActivity");
    LOGE("callJava_thread_func in 3");
    jmethodID method1 = env->GetStaticMethodID(clazz_global,"nativeCall","(Ljava/lang/String;)V");
    LOGE("callJava_thread_func in 4");
    jstring result = env->NewStringUTF("BBBBBBBBB");
    env->CallStaticVoidMethod (clazz_global, method1,result);
    LOGE("callJava_thread_func in 5");

    jmethodID method2 = env->GetMethodID(clazz_global,"nativeCall_nonStatic","(Ljava/lang/String;)V");
    LOGE("callJava_thread_func in 6");
    env->CallVoidMethod (object_global, method2,result);
    LOGE("callJava_thread_func in 7");
    savedVm->DetachCurrentThread();
}



JNIEnv *getEnv() {
    JNIEnv *env = NULL;
    if (savedVm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
        env = NULL;
    }
    return env;
}

test.h

#ifndef JNIC2JAVA_TEST_H
#define JNIC2JAVA_TEST_H

#endif //JNIC2JAVA_TEST_H

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <jni.h>
#include <assert.h>
#include <android/log.h>

extern JavaVM *savedVm;
extern jclass clazz_global;//用于在多线程中回调java中的方法。
extern jobject object_global;

void testCallJavaInThread();
extern void* testcallJava_thread_func(void* p);

test.cpp

#include "test.h"
#include "onload.h"
#include<pthread.h>
#include <assert.h>
#include <android/log.h>

#define TAG "myDemo-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型


void testCallJavaInThread(){
//    pthread_t testnative_thread;
//    pthread_create(&testnative_thread, NULL, testcallJava_thread_func,NULL);
    testcallJava_thread_func(NULL);
}
void* testcallJava_thread_func(void* p){
    LOGE("testcallJava_thread_func in 1");
    JNIEnv *env ;
    if(savedVm == NULL){
        LOGE("savedVm == NULL");
    }
    if (savedVm->AttachCurrentThread(&env, 0) != 0)
    {
        LOGE("Failed to attach current thread");
        return 0;
    }
    LOGE("testcallJava_thread_func in 2");
//    jclass clazz = env->FindClass("com/goertek/jni/MainActivity");//在多线程中FindClass会报错
    LOGE("testcallJava_thread_func in 3");
    jmethodID method1 = env->GetStaticMethodID(clazz_global,"nativeCall","(Ljava/lang/String;)V");
    LOGE("testcallJava_thread_func in 4");
    jstring result = env->NewStringUTF("BBBBBBBBB");
    env->CallStaticVoidMethod (clazz_global, method1,result);
    LOGE("testcallJava_thread_func in 5");


    jmethodID method2 = env->GetMethodID(clazz_global,"nativeCall_nonStatic","(Ljava/lang/String;)V");
    LOGE("testcallJava_thread_func in 6");
    env->CallVoidMethod (object_global, method2,result);
    LOGE("testcallJava_thread_func in 7");
    savedVm->DetachCurrentThread();//不调用这一句,会报错
}

Android.mk

LOCAL_PATH:=$(call my-dir)

 include $(CLEAR_VARS)
 LOCAL_SRC_FILES:= \
    onload.cpp\
    test.cpp\
 LOCAL_MODULE:=hello
 LOCAL_LDLIBS :=-llog
 include $(BUILD_SHARED_LIBRARY)

Application.mk

APP_PLATFORM := android-21
APP_ABI := armeabi-v7a
#APP_OPTIM := debug
APP_OPTIM := release
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值