前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android基础--JNI

Android基础--JNI

作者头像
小蚂蚁与大象
发布2020-04-17 17:56:51
1.1K0
发布2020-04-17 17:56:51
举报

1 JNI_OnLoad

Dalvik虚拟机加载C库时,即执行System.loadLibrary()函数时,第一件事是调用JNI_OnLoad()函数。可以在JNI_OnLoad 去注册方法

代码语言:javascript
复制
JNI_OnLoad --> registerNativeMethods

Android系统加载JNI Lib的方式

  1. 通过JNI_OnLoad
  2. 如果JNI Lib没有定义JNI_OnLoad,则dvm调用dvmResolveNativeMethod进行动态解析

2 JavaVM

JavaVM 是 Java虚拟机在 JNI 层的代表, JNI 全局只有一个, 即一个进程只有一个。

3 JNIEnv

顾名思义,指代了Java本地接口环境(Java Native Interface Environment),是一个JNI接口指针,指向了本地方法的一个函数表,该函数表中的每一个成员指向了一个JNI函数,本地方法通过JNI函数来访问JVM中的数据结构

3.1 JNIEnv 作用

调用 Java 函数 : JNIEnv 代表 Java 运行环境, 可以使用 JNIEnv 调用 Java 中的代码; 操作 Java 对象 : Java 对象传入 JNI 层就是 Jobject 对象, 需要使用 JNIEnv 来操作这个 Java 对象

3.2 JNIEnv 与线程

JNIEnv指针只在它所在的线程中有效,不能跨线程传递和使用。不同线程调用一个本地方法时,传入的JNIEnv指针是不同的. 比如,在jni的方法中起了线程去处理事件,处理完后希望能通知java层,线程中是不能使用参数JNIEnv的。 解决的方法可以通过JavaVM 的AttachCurrentThread方法去获取当前线程的JNIEnv

A JNI interface pointer (JNIEnv*) is passed as an argument for each native function mapped to a Java method, allowing for interaction with the JNI environment within the native method.This JNI interface pointer can be stored, but remains valid only in the current thread. Other threads must first call AttachCurrentThread()to attach themselves to the VM and obtain a JNI interface pointer. Once attached, a native thread works like a regular Java thread running within a native method. The native thread remains attached to the VM until it callsDetachCurrentThread() to detach itself.[3

如果在当前线程调用了DetachCurrentThread() 程序会报错, JDK1.2以后提供了一个新调用接口(invocation interface)函数GetEnv,这样,你就可以检查当前线程是否被附加到JVM上,然后返回属于当前线程的JNIEnv指针。如果当前线程已经被附加到VM上的话,GetEnv和AttachCurrentThread在功能上是等价的。

代码语言:javascript
复制
    int status = javaVM->GetEnv((void**)&env, JNI_VERSION_1_4);
    if (status < 0) {
        javaVM->AttachCurrentThread(&env, NULL);
        ALOGE("AttachCurrentThread");
    }
    ...
    if (status < 0) {
        javaVM->DetachCurrentThread();
    }

4 jobject与jclass类型

object与jclass通常作为JNI函数的第二个参数,当所声明Native方法是静态方法时,对应参数jclass,因为静态方法不依赖对象实例,而依赖于类,所以参数中传递的是一个jclass类型。相反,如果声明的Native方法时非静态方法时,那么对应参数是jobject。

jobject 也是不能跨线程调用的。解决的方法是通过全局引用来获取 env->NewGlobalRef(obj)

代码语言:javascript
复制
JavaVM *g_jvm = NULL;
jobject g_obj = NULL;
//由java调用来建立JNI环境
JNIEXPORT void Java_****_setJNIEnv( JNIEnv* env, jobject obj)
 {
     //保存全局JVM以便在子线程中使用
     env->GetJavaVM(&g_jvm);
     //不能直接赋值(g_obj = obj)
     g_obj = env->NewGlobalRef(obj);
 }
//线程里面
     JNIEnv *env;
     jclass cls;
     jmethodID mid;
 
     //Attach主线程
     if(g_jvm->AttachCurrentThread(&env, NULL)  !=  JNI_OK)
     {
         return NULL;
     }
     //找到对应的类
     cls = env->GetObjectClass(g_obj);
     if(cls == NULL)
     {
         goto error;
     }
     //再获得类中的方法
     mid = env->GetMethodID(cls, "fromJNI", "(I)V");
     if (mid == NULL)
     {
         goto error; 
     }
     //最后调用java中的静态方法
     env->CallVoidMethod(cls, mid ,(int)arg);
 
error:
     return NULL;

不再使用时记得调用相关函数去释放

代码语言:javascript
复制
g_vm->DetachCurrentThread();
env->DeleteLocalRef(g_obj);

参考: https://blog.csdn.net/fireroll/article/details/50102009 https://blog.csdn.net/CV_Jason/article/details/80026265 https://blog.csdn.net/u011068702/article/details/78066746

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 JNI_OnLoad
  • 2 JavaVM
  • 3 JNIEnv
    • 3.1 JNIEnv 作用
      • 3.2 JNIEnv 与线程
      • 4 jobject与jclass类型
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档