JNI编程(C C++ JNI之间的调用)

 -- C语言写JNI方法的过程中,不用编译JNI .h头文件,但是实现Java代码中定义的native方法时,还是得写全native方法的全路径,如JNIEXPORT void JNICALL Java_com_desaco_practiceknowing_native_1method_JniInvokeJava_reflectJava(JNIEnv *, jobject, jstring);

  C++语言写JNI方法的过程中,要编译JNI .h头文件,并且引用头文件,写全native方法的全路径。

JNI接口与接口指针,JNI环境与指针,JNI二进制兼容,类加载器和JVM,JNI移位与反移位,JNI多线程与线程死锁?

> JNI 资源释放,获取上下文Context,加密

JNI 资源释放- https://blog.csdn.net/ccm_oliver/article/details/12781319

Android JNI获取上下文Context- https://blog.csdn.net/lb377463323/article/details/75315167

Android学习JNI,使用JNI实现字符串加密- https://blog.csdn.net/longwang155069/article/details/47808209

JNI接口实现Java和C的交互- http://blog.csdn.net/linzhuowei0775/article/details/49965877

-- JNI 打印Log
#define LOGI(format, ...) __android_log_print(ANDROID_LOG_INFO, "(^_^)", format, ##__VA_ARGS__)
#define LOGE(format, ...) __android_log_print(ANDROID_LOG_ERROR, "(>_<)", format, ##__VA_ARGS__)
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "ProjectName", __VA_ARGS__) 
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , "ProjectName", __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO  , "ProjectName", __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN  , "ProjectName", __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR  , "ProjectName", __VA_ARGS__)
LOGI("user info----name:%s, age:%d, sex:%s.", "xxx", 18, "男");
LOGD("log.d 这是Jni中的log: Java_cn_hpc_cai_jni_JniLogDemo_test()");  
LOGI("Log.i 这是Jni中的log: Java_cn_hpc_cai_jni_JniLogDemo_test()");

LOGD("########## i = %d", i); 

-- 编写JNI需要注意的:
 1. 错误检查
编写本地方法时,最常见的错误就是忘记检查是否发生了异常。所以我们需要注意在平时的编码中,注意检查和处理。
 2. 不要向JNI函数传递非法参数
JNI函数不会检查参数是否正确,尽量保证函数的正确性。否则会发生未知的错误。
 3. 区别 jclass 和 jobject
对象引用对应的是jobject,类引用对应的是jclass。像GetFieldID函数需要传入jclass作为参数,因为它是从一个类中获取某个字段的描述。而GetIntField函数则需要传入jobject,因为它从一个对象实例中获取字段的值。GetStaticXXXField传入的参数是jclass,顾名思义,static是静态的,属于类,而不属于对象。
 4. jboolean数据截取问题
jboolean是一个8-bit unsigned的C类型。可以存储0~255的值。0对应JNI_FALSE,则1~255对应JNI_TRUE。但是32或者16位的值,如果低8位是0的话,就会被截取出来使用,即0。看如下代码:
 5. 编程时,怎么用C
(1)尽量少写本地代码。
(2)让本地代码尽量独立。实际使用中,尽量让所有本地方法在同一个包甚至是同一个类。
 6. ID唯一
本地代码可以创建多个引用并让其指向同一个对象。而字段和方法ID是唯一的。比如类A中定义个F方法,而B类从类A中继承了F方法。但通过GetMethodID方法获取的ID是相同的。
 7. ID缓存
一般情况下,尽量使用全局缓存ID的方式来缓存。
 8. 确保释放内存资源
在编写本地方法时,一定要记得在使用完毕资源后对其进行释放操作。尤其是在分支结构代码中。外部释放后,在分支代码中,如果代码返回,也需要立刻释放。
 9. 过多的创建局部引用,需要及时手动释放
大量的创建局部引用会浪费不必要的内存。一个局部引用会导致它本身和它所指向的对象都得不到回收释放。尤其要注意长时间运行的方法,循环,工具函数。充分利用PushLocalFrame和PopLocalFrame方法来管理局部引用。
 10. 不要使用失效的局部引用
局部引用只在一个本地方法的调用期间有效,方法执行完毕,局部引用就会被自动回收释放,本地代码不应该把局部引用存储到全局变量中,然后在其他地方使用。
 11. 不能跨进程使用JNIEnv

JNIEnv这个指针只能在当前线程使用,不要再其它线程中跨进程使用。

-- Android开发实践:Java层与Jni层的数组传递- https://blog.csdn.net/xinchen200/article/details/25333047
  JNI接口指针只在当前线程中有效。因此,本地方法不能将接口指针从一个线程传递到另一个线程中。实现JNI的虚拟机可将本地线程的数据分配和储存在JNI接口指针所指向的区域中。本地方法将JNI接口指针当作参数来接受。虚拟机在从相同的Java线程中对本地方法进行多次调用时,保证传递给该本地方法的接口指针是相同的。但是,一个本地方法可被不同的Java线程所调用,因此可以接受不同的JNI接口指针。
  -- 在创建支持的C/C++程序中添加两个方法,分别是非静态和静态
public native String stringFromJNI1();
public static native String stringFromJNI2();
  JNI代码:
extern "C"
JNIEXPORT jstring JNICALL
Java_fj_clover_ndktest_MainActivity_stringFromJNI1(JNIEnv *env, jobject instance) {

    // TODO
    return env->NewStringUTF(returnValue);
}
extern "C"
JNIEXPORT jstring JNICALL
Java_fj_clover_ndktest_MainActivity_stringFromJNI2(JNIEnv *env, jclass type) {
    // TODO
    return env->NewStringUTF(returnValue);
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值