#include <jni.h>
#include <string>
#include <stdlib.h>
int compare(const jint *a, const jint *b) {
return *a - *b;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_sort(JNIEnv *env, jclass type, jintArray array_) {
jint *intArray = env->GetIntArrayElements(array_, NULL);
jsize length = env->GetArrayLength(array_);
//排序
//void *ptr 指向待排序的数组的指针
//size_t count 数组的元素数目
//size_t size 数组每个元素的字节大小
// int (*comp)(const void *, const void *) 比较函数。若首个参数小于第二个,则返回负整数值,若首个参数大于第二个,
// 则返回正整数值,若两参数相等,则返回零。
// void qsort( void *ptr, size_t count, size_t size,int (*comp)(const void *, const void *) );
qsort(intArray, static_cast<size_t>(length), sizeof(int),
reinterpret_cast<int (*)(const void *, const void *)>(compare));
//mode =
//0 表示 既要同步数据给jArray,又要释放intArray
//JNI_COMMIT : copy content, do not free buffer ,会同步数据给jArray,但是不会释放intArray
//JNI_ABORT : free buffer w/o copying back ,不会同步数据给jArray,但是会释放intArray
env->ReleaseIntArrayElements(array_, intArray, JNI_ABORT);
}
2.局部引用和全局引用
//局部变量
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_localRef(JNIEnv *env, jclass type) {
//在Native层侯建的Java对象,不用了该怎么管理? 需要手动回收
//在Java层开辟的内存由谁管理(JavaGC管理),能开辟多大内存?
//字符串截取
jclass str_clz = env->FindClass("java/lang/String");
jmethodID init_str = env->GetMethodID(str_clz, "<init>", "()V");
jobject j_str = env->NewObject(str_clz, init_str);
//.....
//jobject不使用了,需要回收。删除了就不能使用了
env->DeleteLocalRef(j_str);
}
//全局变量,需要在合适的时机去释放 env->DeleteGlobalRef(globalStr);删除之后不能使用
jstring globalStr;
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_saveGlobalRef(JNIEnv *env, jclass type, jstring str_) {
globalStr = static_cast<jstring>(env->NewGlobalRef(str_));
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_zzw_jnidemo_ArrayUtils_getStrGlobalRef(JNIEnv *env, jclass type) {
return globalStr;
}
3.静态缓存策略
//局部静态缓存
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_staticLcalCache(JNIEnv *env, jclass type, jstring name_) {
// jfieldID f_id =NULL;
static jfieldID f_id = NULL;//局部缓存 ,这个方法会被多次调用,不需要反复去获取jfieldID
if (!f_id) {
f_id = env->GetStaticFieldID(type, "name", "Ljava/lang/String;");
} else {
LOGE("f_id不为null");//加上static将会缓存
}
env->SetStaticObjectField(type, f_id, name_);
}
//全局静态缓存
static jfieldID jfieldID1;
static jfieldID jfieldID2;
static jfieldID jfieldID3;
//一般初始化的时候调用
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_initStatic(JNIEnv *env, jclass type) {
jfieldID1 = env->GetStaticFieldID(type, "name", "Ljava/lang/String;");
jfieldID2 = env->GetStaticFieldID(type, "name1", "Ljava/lang/String;");
jfieldID3 = env->GetStaticFieldID(type, "name2", "Ljava/lang/String;");
}
//如果反复调用设置值得函数,那么将不会每次都获取id
void setData(JNIEnv *env, jclass jclazz, jobject object) {
env->SetStaticObjectField(jclazz, jfieldID1, object);
env->SetStaticObjectField(jclazz, jfieldID2, object);
env->SetStaticObjectField(jclazz, jfieldID3, object);
}
4.异常处理
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnidemo_ArrayUtils_exception2(JNIEnv *env, jclass cls) {
jthrowable exc = NULL;
jmethodID mid = env->GetStaticMethodID(cls, "exceptionCallback", "()V");
if (mid != NULL) {
env->CallStaticVoidMethod(cls, mid);
}
LOGE("In C: Java_com_zzw_jnidemo_ArrayUtils_exception2-->called!!!!");
//这种也是可以检测的
// exc = env->ExceptionOccurred(); // 返回一个指向当前异常对象的引用
// if (exc) {
if (env->ExceptionCheck()) { // 检查JNI调用是否有引发异常
env->ExceptionDescribe();//打印错误信息
env->ExceptionClear(); // 清除引发的异常,在Java层不会打印异常的堆栈信息
env->ThrowNew(env->FindClass("java/lang/Exception"), "JNI抛出的异常!");
return;
}
//补救 。。。
mid = env->GetStaticMethodID(cls, "normalCallback", "()V");
if (mid != NULL) {
env->CallStaticVoidMethod(cls, mid);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
ArrayUtils.exception();
} catch (Exception e) {
e.printStackTrace();//打印抛出的异常
}
}
env
调用即可,在子线程调用则需要JavaVM ->AttachCurrentThread
拿到env
然后调用。
#include "JavaListener.h"
JavaVM *jvm;
JavaListener *javaListener;
pthread_t chidlThread;
void *childCallback(void *data)
{
JavaListener *javaListener1 = (JavaListener *) data;
//子线程调用
javaListener1->onError(0, 101, "c++ call java meid from child thread!");
pthread_exit(&chidlThread);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_zzw_jnithread_ThreadDemo_callbackFromC(JNIEnv *env, jobject instance) {
javaListener = new JavaListener(jvm, env, env->NewGlobalRef(instance));
//主线程调用
//javaListener->onError(1, 100, "c++ call java meid from main thread!");
//子线程调用
pthread_create(&chidlThread, NULL, childCallback, javaListener);
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void* reserved)
{
JNIEnv *env;
jvm = vm;
if(vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK)
{
return -1;
}
return JNI_VERSION_1_6;
}
JavaListener.h
#include "jni.h"
#ifndef JNITHREAD_JAVALISTENER_H
#define JNITHREAD_JAVALISTENER_H
class JavaListener {
public:
JavaVM *jvm;
_JNIEnv *jenv;
jobject jobj;
jmethodID jmid;
public:
JavaListener(JavaVM *vm, _JNIEnv *env, jobject obj);
~JavaListener();
/**
* 1:主线程
* 0:子线程
* @param type
* @param code
* @param msg
*/
void onError(int type, int code, const char *msg);
};
#endif //JNITHREAD_JAVALISTENER_H
JavaListener.cpp
#include "JavaListener.h"
void JavaListener::onError(int type, int code, const char *msg) {
if(type == 0)
{
JNIEnv *env;
jvm->AttachCurrentThread(&env, 0);
jstring jmsg = env->NewStringUTF(msg);
env->CallVoidMethod(jobj, jmid, code, jmsg);
env->DeleteLocalRef(jmsg);
jvm->DetachCurrentThread();
}
else if(type == 1)
{
jstring jmsg = jenv->NewStringUTF(msg);
jenv->CallVoidMethod(jobj, jmid, code, jmsg);
jenv->DeleteLocalRef(jmsg);
}
}
JavaListener::JavaListener(JavaVM *vm, _JNIEnv *env, jobject obj) {
jvm = vm;
jenv = env;
jobj = obj;
jclass clz = env->GetObjectClass(jobj);
if(!clz)
{
return;
}
jmid = env->GetMethodID(clz, "onError", "(ILjava/lang/String;)V");
if(!jmid)
return;
}
ThreadDemo.java
public class ThreadDemo {
static
{
System.loadLibrary("native-lib");
}
private OnErrerListener onErrerListener;
public void setOnErrerListener(OnErrerListener onErrerListener) {
this.onErrerListener = onErrerListener;
}
public void onError(int code, String msg)
{
if(onErrerListener != null)
{
onErrerListener.onError(code, msg);
}
}
public interface OnErrerListener
{
void onError(int code, String msg);
}
public native void callbackFromC();
}
-------------The End-------------