`
mfcai
  • 浏览: 409364 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

深入了解android平台的jni---本地多线程调用java代码

阅读更多
一、jni调用java对象
    JNI提供的功能之一是在本地代码中使用Java对象。包括:创建一个java类对象和通过函数传递一个java对象。创建一个java类对象,首先需要得到得到使用FindClass/GetObjectClass函数得到该类,然后使用GetMethodID方法得到该类的方法id,然后调用该函数。 Java 和 Native 代码之间函数调用时,如果是简单类型,也就是内置类型,比如 int, char 等是值传递(pass by value),而其它 Java 对象都是引用传递(pass by reference),这些对象引用由 JVM 传给 Native 代码。
在本地方法中调用Java对象的方法的步骤:
1)获取你需要访问的Java对象的类
FindClass通过传java中完整的类名来查找java的class
GetObjectClass通过传入jni中的一个java的引用来获取该引用的类型。
他们之间的区别是,前者要求你必须知道完整的类名,后者要求在Jni有一个类的引用。
2)获取MethodID,调用方法
GetMethodID 得到一个实例的方法的ID
GetStaticMethodID 得到一个静态方法的ID
3)获取对象的属性
GetFieldID 得到一个实例的域的ID
GetStaticFieldID 得到一个静态的域的ID
JNI通过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。

二、jni中引用的java对象的生命周期
Java对象做为引用被传递到本地方法中,所有这些Java对象的引用都有一个共同的父类型jobject(相当于java中的 Object类是所有类的父类一样)。 这些对象引用都有其生命周期。在JNI中对Java对象的引用根据生命周期分为:全局引用,局部引用、弱全局引用
1、Local Reference 本地引用,
函数调用时传入jobject或者jni函数创建的jobejct,都是本地引用.
其特点就是一旦JNI层函数返回,jobject就被垃圾回收掉,所以需要注意其生命周期。可以强制调用DeleteLocalRef进行立即回收。
jstring pathStr = env->NewStringUTF(path)
....
env->DeleteLocalRef(pathStr);
2、Global Reference 全局引用 ,这种对象如不主动释放,它永远都不会被垃圾回收
创建: env->NewGlobalRef(obj);
释放: env->DeleteGlobalRef(obj)
若要在某个 Native 代码返回后,还希望能继续使用 JVM 提供的参数, 或者是过程中调用 JNI 函数的返回值(比如 g_mid), 则将该对象设为 global reference,以后只能使用这个 global reference;若不是一个 jobject,则无需这么做。
3、Weak Global Reference 弱全局引用
一种特殊的 Global Reference ,在运行过程中可能被垃圾回收掉,所以使用时请务必注意其生命周期及随时可能被垃圾回收掉,比如内存不足时。
使用前可以利用JNIEnv的 IsSameObject 进行判定它是否被回收
env->IsSameObject(obj1,obj2);


三、本地线程中调用java对象
问题1:
JNIEnv是一个线程相关的变量
JNIEnv 对于每个 thread 而言是唯一的
JNIEnv *env指针不可以为多个线程共用
解决办法:
但是java虚拟机的JavaVM指针是整个jvm公用的,我们可以通过JavaVM来得到当前线程的JNIEnv指针.
可以使用javaAttachThread保证取得当前线程的Jni环境变量
static JavaVM *gs_jvm=NULL;
gs_jvm->AttachCurrentThread((void **)&env, NULL);//附加当前线程到一个Java虚拟机
jclass cls = env->GetObjectClass(gs_object);
jfieldID fieldPtr = env->GetFieldID(cls,"value","I");
问题2:
不能直接保存一个线程中的jobject指针到全局变量中,然后在另外一个线程中使用它。
解决办法:
用env->NewGlobalRef创建一个全局变量,将传入的obj(局部变量)保存到全局变量中,其他线程可以使用这个全局变量来操纵这个java对象
注意:若不是一个 jobject,则不需要这么做。如:
jclass 是由 jobject public 继承而来的子类,所以它当然是一个 jobject,需要创建一个 global reference 以便日后使用。
而 jmethodID/jfieldID 与 jobject 没有继承关系,它不是一个 jobject,只是个整数,所以不存在被释放与否的问题,可保存后直接使用。
static jobject gs_object=NULL;
JNIEXPORT void JNICALL Java_Test_setEnev(JNIEnv *env, jobject obj)
{
    env->GetJavaVM(&gs_jvm); //保存到全局变量中JVM
    //直接赋值obj到全局变量是不行的,应该调用以下函数:
    gs_object=env->NewGlobalRef(obj);
}


jni部分代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>

#include<jni.h>
#include<android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-activity", __VA_ARGS__))


//全局变量
JavaVM *g_jvm = NULL;
jobject g_obj = NULL;
void *thread_fun(void* arg)
{
     JNIEnv *env;
     jclass cls;
     jmethodID mid;


     //Attach主线程
     if((*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL) != JNI_OK)
     {
         LOGE("%s: AttachCurrentThread() failed", __FUNCTION__);
         return NULL;
     }
     //找到对应的类
     cls = (*env)->GetObjectClass(env,g_obj);
     if(cls == NULL)
     {
         LOGE("FindClass() Error.....");
         goto error;
     }
     //再获得类中的方法
     mid = (*env)->GetMethodID(env, cls, "fromJNI", "(I)V");
     if (mid == NULL)
     {
         LOGE("GetMethodID() Error.....");
         goto error;
     }
     //最后调用java中的静态方法
         (*env)->CallVoidMethod(env, cls, mid ,(int)arg);
  


error:  
     //Detach主线程
     if((*g_jvm)->DetachCurrentThread(g_jvm) != JNI_OK)
     {
         LOGE("%s: DetachCurrentThread() failed", __FUNCTION__);
     }
   


     pthread_exit(0);
}


//由java调用以创建子线程
JNIEXPORT void Java_com_test_JniThreadTestActivity_mainThread( JNIEnv* env, jobject obj, jint threadNum)
{
     int i;
     pthread_t* pt;
     pt = (pthread_t*) malloc(threadNum * sizeof(pthread_t));
     for (i = 0; i < threadNum; i++){
         //创建子线程
        pthread_create(&pt[i], NULL, &thread_fun, (void *)i);
}

for (i = 0; i < threadNum; i++){
pthread_join (pt[i], NULL);
}
LOGE("main thread exit.....");
}




//由java调用来建立JNI环境
JNIEXPORT void Java_com_test_JniThreadTestActivity_setJNIEnv( JNIEnv* env, jobject obj)
{
     //保存全局JVM以便在子线程中使用
     (*env)->GetJavaVM(env,&g_jvm);
     //不能直接赋值(g_obj = obj)
     g_obj = (*env)->NewGlobalRef(env,obj);
}




//当动态库被加载时这个函数被系统调用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
     JNIEnv* env = NULL;
     jint result = -1;  


     //获取JNI版本
     if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK)
     {
         LOGE("GetEnv failed!");
             return result;
     }


     return JNI_VERSION_1_4;
}
需要全部源码的,可以自行下载.代码编译通过,导入Eclipse,便可运行



本文欢迎转载,转载请注明出处与作者
出处:http://blog.sina.com.cn/staratsky
作者:流星
分享到:
评论

相关推荐

    jni中用多线程调用java代码

    总结,本项目展示了如何在Android的JNI环境中利用多线程调用Java代码,这对于理解和实践JNI、线程管理和跨语言编程有着重要的教育价值。通过实践这个项目,开发者可以提高自己在Android原生开发和性能优化方面的技能...

    Android JNI多线程编程回调JAVA函数

    总之,Android中的JNI多线程编程和回调Java函数是一项重要的技能,它能有效利用多核处理器的性能,提高程序效率,并实现复杂的功能。理解并熟练运用这些技术,将有助于提升Android应用的性能和质量。

    jni-android-studio1.3.1

    JNI,全称Java Native Interface,是Java平台标准的一部分,它为Java程序员提供了一种方法,可以在Java代码中调用本地(非Java)代码,反之亦然。在Android开发中,JNI有着广泛的应用,例如实现高性能的计算、调用...

    Android开发书籍 - JNI详解-导航版

    * 并发编程:并发编程是指多线程编程,JNI 使得 Java 代码可以和本地代码共享内存空间,并实现多线程编程。 * 并发编程的实现:并发编程的实现是通过 Java 虚拟机和本地库之间的接口定义来实现的。 本书籍是 ...

    JNI-study(讲JNI的书,中文版)

    JNI,全称Java Native Interface,是Java平台标准的一部分,它为Java程序员提供了一种方法,可以在Java代码中直接调用本地(非Java)代码,反之亦然。这使得开发者能够利用Java的高级特性同时利用C/C++等语言的高效...

    ffmpeg-jni-x265

    在Android平台上,由于系统对原生代码的支持,我们可以通过Java Native Interface (JNI)来调用FFmpeg库,实现高效能的音视频处理。`ffmpeg-jni-x265`是一个特别针对Android定制的版本,它集成了x265编码器,能够帮助...

    Android JNI调用-文件操作

    在Android开发中,JNI(Java Native Interface)是一个关键特性,它允许Java代码和其他语言写的代码进行交互。JNI在很多场景下都非常有用,比如优化性能、访问特定硬件功能、调用已有的C/C++库等。在本教程中,我们...

    webrtc-android-jni.rar

    在Android平台上,WebRTC的实现涉及到JNI(Java Native Interface),这是Java平台用来调用C/C++原生代码的接口。 在这个"webrtc-android-jni.rar"压缩包中,我们可以推测其内容可能与Android应用开发中集成WebRTC...

    android-ndk-jni示例代码

    JNI(Java Native Interface)是Java平台的标准接口,它使得Java代码能够调用本地(native)代码,也就是非Java语言编写的代码,如C++或C。Android NDK则是一个提供给开发者编译原生代码的工具集,它包含了用于交叉...

    JniCallback.zip_Android jni_android_jni android_jni callback_jni

    JNI回调机制允许本地代码调用Java对象的方法,这在处理异步事件、周期性任务或需要从本地代码触发Java方法的情况时非常有用。在Android应用中,我们通常会定义一个Java类,该类包含一个本地方法声明,并在本地代码...

    JNI-增量升级Demo

    在Android应用开发中,JNI(Java Native Interface)是一种让Java代码与本地C/C++代码交互的技术,它允许开发者利用C/C++的高效性能处理特定任务,例如底层计算、图形渲染或者与硬件设备交互。本“JNI-增量升级Demo...

    Android开发书籍 - JNI详解_导航版

    - **JNI的双向调用**:不仅可以从Java代码调用C/C++代码,还可以从C/C++代码调用Java代码,这意味着两种语言之间的完全互操作性。 - **JNI与Java虚拟机**:JNI是Java平台的一部分,因此它必须遵循Java平台的规范。...

    android调用jni实例

    通过这个实例,我们了解到Android应用如何利用JNI调用本地代码,以及在不同平台(Windows、Mac、Linux)上如何使用NDK进行编译和调试。此外,NDK还支持更复杂的功能,如多线程、OpenSSL、OpenCV等库的集成,使得...

    hello-jni.rar_ android jni_android hello jni_android jni hellojn

    了解了基本的JNI开发流程后,可以深入研究更多高级主题,如多线程支持、错误处理、资源管理等。此外,NDK还提供了对C++11、OpenMP、Android Hal层接口等功能的支持,使得原生开发更具扩展性。 总结,Android NDK和...

    serial_jni_largestgle_Androidjni_Android串口操作JNI代码_android_

    `serial_jni_largestgle_Androidjni_Android串口操作JNI代码_android_`这个项目就是关于如何使用JNI来实现Android设备的串口读写的示例。 首先,我们需要了解JNI的概念。JNI是Java平台提供的一种接口,允许Java代码...

    Android 5.0jni调用

    6. **线程安全**:在Android 5.0中,JNI函数默认运行在主线程之外,开发者需要注意多线程环境下的同步问题。正确地管理和同步本地资源,避免数据竞争,是保证应用稳定的关键。 7. **错误处理**:Android 5.0提供了...

    android-ndk-r18b-windows-x86_64.zip

    5. **JNI(Java Native Interface)**:NDK提供与Java代码交互的能力,通过JNI接口,Java和原生代码可以相互调用。 在Android NDK R18B版本中,包含了以下特性: 1. **更新的编译器和工具链**:R18B可能包含了GCC...

    jni-bridge.rar_jni

    4. **调用Java方法**:在C/C++代码中,我们可以使用JNI接口来访问和操作Java对象。例如,可以创建新对象、调用方法、获取字段值等。 5. **错误处理**:在JNI编程中,错误处理是必不可少的。如果在注册过程中发生...

    android jni调用jni 方法

    - JNI是一种接口,让Java应用程序能够调用本地(非Java)代码,同时也允许本地代码调用Java方法。 - 在Android中,JNI通常用于实现Java与C/C++之间的数据交换,提高性能,或者利用现有的C/C++库。 2. **创建JNI...

    android_jni.rar_android_android_jni

    Android JNI(Java Native Interface)是Android系统中用于Java与C/C++代码交互的桥梁,它允许开发者在Android应用中调用本地方法,实现性能优化、使用已有的C库或者访问硬件设备等功能。这个"android_jni.rar...

Global site tag (gtag.js) - Google Analytics