package com.tz.ndk;
import java.util.Random;
public class NDKInterface {
// 内容一:数组操作
// Java传递一个数组到C中,C需要对数组进行排序
public native void softArray(int[] intArray);
// 在C中产生一个指定大小的数组,返回到Java中
public native int[] getNativeArray(int len);
// 内容二:JNI引用
// jni中:局部引用
public native void localRef();
// 创建全局引用
public native void setGlobleRef();
// 得到一个全局引用
public native String getGlobleRef();
// 是否全局引用
public native void releaseGlobleRef();
// 内容三:异常处理
public native int exception();
// 手动抛出异常,我们在java程序中普获
public native int customerException();
// 内容四:缓存策略
// 有两种缓存(在JNI中,说白了就是C/C++中):
//第一种:static静态方式实现
private String name = "Dream";
public native int staticCached();
//第二种:初始化方式(当我们的动态库加载的时候初始化一些数据)
public static native void initCached();
// 产生一个随机数
public int getIntRandom(int max) {
return new Random().nextInt(max);
}
static {
System.loadLibrary("NDK_JNI_10");
initCached();
}
}
package com.tz.ndk;
import android.app.Activity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// softArray();
getNativeArray();
// getGlobleRef();
// exception();
// customerException();
// staticCached();
}
// public void staticCached() {
// NDKInterface ndkInterface = new NDKInterface();
// for (int i = 0; i < 10; i++) {
// int staticCached = ndkInterface.staticCached();
// Log.i("main", "返回结果:" + staticCached);
// }
// }
public void customerException() {
NDKInterface ndkInterface = new NDKInterface();
try {
ndkInterface.customerException();
} catch (Exception e) {
Log.i("main", "异常信息:" + e.getMessage());
}
}
public void exception() {
NDKInterface ndkInterface = new NDKInterface();
int result = ndkInterface.exception();
Log.i("main", "返回值:" + result);
}
public void softArray() {
int[] intArray = { 23, 5, 1, 67, 349, 2 };
NDKInterface ndkInterface = new NDKInterface();
ndkInterface.softArray(intArray);
for (int i : intArray) {
Log.i("main", "排序之后:" + i);
}
}
public void getNativeArray() {
NDKInterface ndkInterface = new NDKInterface();
int[] nativeArray = ndkInterface.getNativeArray(10);
for (int i : nativeArray) {
Log.i("main", "返回的数组元素:" + i);
}
}
public void getGlobleRef() {
new Thread(new Runnable() {
@Override
public void run() {
NDKInterface ndkInterface = new NDKInterface();
ndkInterface.setGlobleRef();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String globleRef = ndkInterface.getGlobleRef();
Log.i("main", "释放前-全局引用:" + globleRef);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ndkInterface.releaseGlobleRef();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
globleRef = ndkInterface.getGlobleRef();
} catch (Exception e) {
e.printStackTrace();
}
if (TextUtils.isEmpty(globleRef)) {
Log.i("main", "释放后-全局引用:为空");
} else {
Log.i("main", "释放后-全局引用:" + globleRef);
}
}
}).start();
}
}
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := NDK_JNI_10
LOCAL_SRC_FILES := com_tz_ndk_NDKInterface.c
include $(BUILD_SHARED_LIBRARY)
头文件:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_tz_ndk_NDKInterface */
#ifndef _Included_com_tz_ndk_NDKInterface
#define _Included_com_tz_ndk_NDKInterface
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_tz_ndk_NDKInterface
* Method: softArray
* Signature: ([I)V
*/
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_softArray
(JNIEnv *, jobject, jintArray);
/*
* Class: com_tz_ndk_NDKInterface
* Method: getNativeArray
* Signature: (I)[I
*/
JNIEXPORT jintArray JNICALL Java_com_tz_ndk_NDKInterface_getNativeArray
(JNIEnv *, jobject, jint);
/*
* Class: com_tz_ndk_NDKInterface
* Method: localRef
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_localRef
(JNIEnv *, jobject);
/*
* Class: com_tz_ndk_NDKInterface
* Method: setGlobleRef
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_setGlobleRef
(JNIEnv *, jobject);
/*
* Class: com_tz_ndk_NDKInterface
* Method: getGlobleRef
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_tz_ndk_NDKInterface_getGlobleRef
(JNIEnv *, jobject);
/*
* Class: com_tz_ndk_NDKInterface
* Method: releaseGlobleRef
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_releaseGlobleRef
(JNIEnv *, jobject);
/*
* Class: com_tz_ndk_NDKInterface
* Method: exception
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_tz_ndk_NDKInterface_exception
(JNIEnv *, jobject);
/*
* Class: com_tz_ndk_NDKInterface
* Method: customerException
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_tz_ndk_NDKInterface_customerException
(JNIEnv *, jobject);
/*
* Class: com_tz_ndk_NDKInterface
* Method: staticCached
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_tz_ndk_NDKInterface_staticCached
(JNIEnv *, jobject);
/*
* Class: com_tz_ndk_NDKInterface
* Method: initCached
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_initCached
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
#include
#include
#include
#include "com_tz_ndk_NDKInterface.h"
//升序
// int comparate(jint *a,jint *b){
// return (*a) - (*b);
// }
//降序
int comparate(jint *a,jint *b){
return (*b) - (*a);
}
//Java传递一个数组到C中,C需要对数组进行排序
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_softArray
(JNIEnv *env, jobject jobj, jintArray jarr){
//第一步:首先将Java中的数组转成C中的数组(拷贝数据)
jint *elems = (*env)->GetIntArrayElements(env,jarr,NULL);
//第二步:排序(在Java中也有排序提供的API:Collections.sort)
//获取数组的长度
int arr_len = (*env)->GetArrayLength(env,jarr);
//参数一:数组
//参数二:数组的长度
//参数三:每一个元素的大小
//参数四:比较器(排序方式,例如:升序、降序等等......)
qsort(elems,arr_len,sizeof(int),comparate);
//注意:GetIntArrayElements是将数组拷贝了一份
//更新Java数组(同步数据)
//参数一:JNI环境指针
//参数二:源数组(Java中)
//参数三:排序之后的数组
//参数四:模式
//0代表:java数组进行更新,并且释放C/C++中数组
//JNI_ABORT代表:不更新java数组,但是需要释放C/C++数组内存
//JNI_COMMIT代表:更新Java数组,但是不释放C/C++中的数组
(*env)->ReleaseIntArrayElements(env,jarr,elems,0);
}
//在C中产生一个指定大小的数组,返回到Java中
JNIEXPORT jintArray JNICALL Java_com_tz_ndk_NDKInterface_getNativeArray
(JNIEnv *env, jobject jobj, jint jlen){
//第一步:创建一个数组(创建一个Java数组)
jintArray jarr = (*env)->NewIntArray(env,jlen);
//第二步:转成C/C++认识的数组
jint *emls = (*env)->GetIntArrayElements(env,jarr,NULL);
//获取Java中的方法
jclass ndk_obj = (*env)->GetObjectClass(env,jobj);
//获取方法对象
// jmethodID random_mid = (*env)->GetMethodID(env,ndk_obj,"getIntRandom","(I)I");
//赋值
for(int i = 0;i < jlen;i++){
//循环中执行方法
jint result_int = (*env)->CallIntMethod(env,jobj,mid,100);
emls[i] = result_int;
}
//返回(同步)
(*env)->ReleaseIntArrayElements(env,jarr,emls,0);
return jarr;
}
//内容二:JNI引用
//场景:C/C++中必须告诉Java虚拟机(JVM)或者Android虚拟机(Dalvik)
//什么时候你可以回收,什么时候你不能够回收
//所以在JNI中引入了引用
//引用类型:局部引用和全局引用
//讲解:局部引用
//回收规则:局部引用会在C/C++代码执行完毕之后自动回收(自动释放)
//问题:有的时候我们自己需要手动的控制?
//场景
//1、访问java中的大对象(文件操作等等....),要进行一些耗时操作
//2、创建java中大量的局部引用,占用很大的空间(例如:for循环中),
// 然而这些局部引用根后面代码没有什么关联
//演示场景--场景对象数组
//局部引用:C/C++中不能够在多线程中传递
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_localRef
(JNIEnv *env, jobject jobj){
//获取一个类对象(获取java.lang.String)
jclass cls_str = (*env)->FindClass(env,"java/lang/String");
//获取构造方法(实例化)
jmethodID mid_init = (*env)->GetMethodID(env,cls_str,"","()V");
for(int i = 0 ; i < 10 ; i++){
//创建对象
jobject obj_str = (*env)->NewObject(env,cls_str,mid_init);
//创建数组
jobjectArray arr_obj = (*env)->NewObjectArray(env,6,cls_str,obj_str);
//中间省略100行代码
//手动释放数组
(*env)->DeleteLocalRef(env,obj_str);
(*env)->DeleteLocalRef(env,arr_obj);
}
//此处省略200行代码
}
//全局引用
//规则:
//1、可以在多个线程中传递
//2、程序员手动释放之前都是有效的(一直有效)
//创建全局引用
jstring globle_ref;
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_setGlobleRef
(JNIEnv *env, jobject jobj){
jstring str = (*env)->NewStringUTF(env,"Hello world!");
//创建一个全局引用(说白了就是做一个标记)
globle_ref = (*env)->NewGlobalRef(env,str);
}
//获取全局饮用
JNIEXPORT jstring JNICALL Java_com_tz_ndk_NDKInterface_getGlobleRef
(JNIEnv *env, jobject jobj){
return globle_ref;
}
//手动释放
//注意:释放之后,android中不能获取,因为是NULL,不能够转成String
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_releaseGlobleRef
(JNIEnv *env, jobject jobj){
//释放全局引用
(*env)->DeleteGlobalRef(env,globle_ref);
}
//异常处理
//总结一:JNI函数执行的过程中,抛出了Java异常不回终止程序的继续运行
// 但是发生错误(error),那么就好终止程序的继续运行
//例如:我的女朋友不给我煮饭,我不会饿死,但是我自己不煮饭就饿死
JNIEXPORT jint JNICALL Java_com_tz_ndk_NDKInterface_exception
(JNIEnv *env, jobject jobj){
//获取Java中的方法
jclass ndk_obj = (*env)->GetObjectClass(env,jobj);
//获取方法对象
jmethodID random_mid = (*env)->GetMethodID(env,ndk_obj,"getIntRandom1","(I)I");
//处理异常
//在JNI中我们可以检测是否发生了异常
jthrowable exception = (*env)->ExceptionOccurred(env);
if(exception){
//注意:如果你要在C中处理异常,需要清空,要不然我们Android程序无法往后执行
//将异常情况
(*env)->ExceptionClear(env);
//处理异常(补救措施)
random_mid = (*env)->GetMethodID(env,ndk_obj,"getIntRandom","(I)I");
}
//执行方法
jint result_int = (*env)->CallIntMethod(env,jobj,random_mid,100);
return result_int;
}
//怎么才能够处理异常?
//在JNI中:需要自己手动抛出异常才能够普获
//总结二:通过ThrowNew手动抛出异常,在Java程序中能够普获异常,但是自动抛出异常我们无法普获
JNIEXPORT jint JNICALL Java_com_tz_ndk_NDKInterface_customerException
(JNIEnv *env, jobject jobj){
//处理异常
//在JNI中我们可以检测是否发生了异常
int a = 100;
int b = 200;
if(a != b){
//注意:如果你要在C中处理异常,需要清空,要不然我们Android程序无法往后执行
//将异常情况
//手动抛出异常
jclass such_cls = (*env)->FindClass(env,"java/lang/IllegalArgumentException");
//参数一:环境指针
//参数二:抛异常类型
//参数三:异常信息
(*env)->ThrowNew(env,such_cls,"no such method exception!");
return -1;
}
return 0;
}
//缓存策略
//第一种:static方式缓存
static jfieldID fid_s = NULL;
JNIEXPORT jint JNICALL Java_com_tz_ndk_NDKInterface_staticCached
(JNIEnv *env, jobject jobj){
//通过static缓存属性
//总结:static修饰的属性,能够进行缓存
//static
//局部静态变量:只能作用在当前所在的范围
//全局静态变量:只能够在源文件中使用
static jfieldID fid_s = NULL;
jclass cls = (*env)->GetObjectClass(env,jobj);
jstring jstr;
if (fid_s == NULL){
fid_s = (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;");
return -1;
}
return 0;
}
//初始化方式缓存
jfieldID fid = NULL;
jmethodID mid = NULL;
JNIEXPORT void JNICALL Java_com_tz_ndk_NDKInterface_initCached
(JNIEnv *env, jobject jcls){
fid = (*env)->GetFieldID(env,jcls,"name","Ljava/lang/String;");
mid = (*env)->GetMethodID(env,jcls,"getIntRandom","(I)I");
}
整理自示例代码