NDK-JNI语法-数组处理+全局引用+异常处理+缓存策略

46 篇文章 1 订阅
42 篇文章 0 订阅

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();
	}

}

mk文件:

   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 <jni.h>
/* 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

c文件:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#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,"<init>","()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");
}




整理自示例代码




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值