NDK基础(java ,c/c++, jni之间的关系及java和c/c++之间的相互调用)

时间:2021-02-06 17:23:36

1.java,c/c++,和jni之间的关系

NDK基础(java ,c/c++, jni之间的关系及java和c/c++之间的相互调用)

java和c/c++可以相互调用,是因为java虚拟机中的JNI。简单的说就是用c/c++编写一个动态链接库让Java虚拟机去调用。(在windows环境下动态链接库就是.dll文件,

在Linux下就是.so文件)

2.下面来看一个具体的例子

这个例子是来自书<<Android.NDK.Beginner-'s.Guide>>中的。我们先建一个java,类Store.这个类是用来封c/c++中的方法。我们先来看一下这个类的代码。

public class Store {

static {
System.loadLibrary("store");
}

public native void initializeStore();
public native void finalizeStore();

/**
* Getter/setters on primitives and objects.
*/
public native boolean getBoolean(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setBoolean(String strKey, boolean bValue);

public native byte getByte(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setByte(String strKey, byte btValue);

public native char getChar(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setChar(String strKey, char cValue);

public native double getDouble(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setDouble(String strKey, double dValue);

public native float getFloat(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setFloat(String strKey, float fValue);

public native int getInteger(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setInteger(String strKey, int iVaule);

public native long getLong(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setLong(String strKey, long lValue);

public native short getShort(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setShort(String strKey, short sValue);

public native String getString(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setString(String strKey, String strValue);

public native Color getColor(String strKey)
throws NotExistingKeyException, InvalidTypeException;
public native void setColor(String strKey, Color color);

/**
* Getter/setter on arrays
*/
public native boolean[] getBooleanArray(String strKey)
throws NotExistingKeyException;
public native void setBooleanArray(String strKey, boolean[] bArrayValue);

public native byte[] getByteArray(String strKey)
throws NotExistingKeyException;
public native void setByteArray(String strKey, byte[] btArrayValue);

public native char[] getCharArray(String strKey)
throws NotExistingKeyException;
public native void setCharArray(String strKey, char[] cArrayValue);

public native double[] getDoubleArray(String strKey)
throws NotExistingKeyException;
public native void setDoubleArray(String strKey, double[] dArrayValue);

public native float[] getFloatArray(String strKey)
throws NotExistingKeyException;
public native void setFloatArray(String strKey, float[] fArrayValue);

public native int[] getIntegerArray(String strKey)
throws NotExistingKeyException;
public native void setIntegerArray(String strKey, int[] iArrayValue);

public native long[] getLongArray(String strKey)
throws NotExistingKeyException;
public native void setLongArray(String strKey, long[] lArrayValue);

public native short[] getShortArray(String strKey)
throws NotExistingKeyException;
public native void setShortArray(String strKey, short[] sArrayValue);

public native String[] getStringArray(String strKey)
throws NotExistingKeyException;
public native void setStringArray(String strKey, String[] strArrayValue);

public native Color[] getColorArray(String strKey)
throws NotExistingKeyException;
public native void setColorArray(String strKey, Color[] colorArray);

}


在一开始就加载动态链接库
<span style="color:#33cc00;">static {		System.loadLibrary("store");//这个代码就是加载store库,就是用c/c++编译生成的libstore.so动态链接库,该文件在libs文件下面</span>
<span style="color:#33cc00;">	}</span>
每一个调用c/c++实现的方法时,前面都加上  native 关键字. c/c++我们以这个方法为例

public native boolean getBoolean(String strKey)

throws NotExistingKeyException, InvalidTypeException;

java 中的String的值到底是怎么怎么传递给c/c++的呢?前面的图说了,是JVM的JNI。JNI到底是怎么实现的呢?先看一下,8种基本类型是怎么传递

Java type

JNI type

C type

Stdint C type

boolean

Jboolean

unsigned char

uint8_t

byte

Jbyte

signed char

int8_t

char

Jchar

unsigned short

uint16_t

double

Jdouble

double

double

float

jfloat

float

float

int

jint

Int

int32_t

long

jlong

long long

int64_t

short

jshort

Short

int16_t

我们可以看出,都分别是通过JNI中的jboolean,jbyte,jchar,jdouble,jfloat,jint,jlong,jshort这些一一对应传递过去。
String是怎么传递过去呢,是通过JNI中的jstring.传递。自己写的类可以通过jobject,传递过去。下面,就建一个自己的Color类。
public class Color {
private int miColor;

public Color(String pColor) {
super();
miColor = android.graphics.Color.parseColor(pColor);
}

@Override
public String toString() {
return String.format("#%06X", miColor);
}

}

下面有一个要用到的枚举
public enum StoreType {
Boolean, Byte, Char, Double, Float, Integer, Long, Short,
String, Color,

BooleanArray, ByteArray, CharArray, DoubleArray, FloatArray,
IntegerArray, LongArray, ShortArray, StringArray, ColorArray

}

上面是java中的相关代码,在c中的代码怎么和java相对接呢,先看一下c中代码
/*
* com_packtpub_Store.h
*
* Created on: May 18, 2015
* Author: Lioncraft
*/


#ifndef COM_PACKTPUB_STORE_H_
#define COM_PACKTPUB_STORE_H_

#include <jni.h>

#ifdef __cplusplus
extern "C" {//这个代码如果要时c++,就把接口强转成c的标准接口
#endif
/**
* Class: com_example_packtpub_Store
* Method: initializeStore
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_initializeStore(JNIEnv *, jobject);

/**
* Class: com_example_packtpub_Store
* Method: finalizeStore
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_finalizeStore(JNIEnv *, jobject);

/**
* Class: com_example_packtpub_Store
* Method: getBoolean
* Signature: (Ljava/lang/String;)Z
*/
JNIEXPORT jboolean JNICALL Java_com_example_packtpub_Store_getBoolean(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setBoolean
* Signature: (Ljava/lang/String;Z)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setBoolean(JNIEnv *, jobject, jstring, jboolean);

/**
* Class: com_example_packtpub_Store
* Method: getByte
* Signature: (Ljava/lang/String;)B
*/
JNIEXPORT jbyte JNICALL Java_com_example_packtpub_Store_getByte(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setByte
* Signature: (Ljava/lang/String;B)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setByte(JNIEnv *, jobject, jstring, jbyte);

/**
* Class: com_example_packtpub_Store
* Method: getChar
* Signature: (Ljava/lang/String;)C
*/
JNIEXPORT jchar JNICALL Java_com_example_packtpub_Store_getChar(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setChar
* Signature: (Ljava/lang/String;C)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setChar(JNIEnv *, jobject, jstring, jchar);

/**
* Class: com_example_packtpub_Store
* Method: getDouble
* Signature: (Ljava/lang/String;)D
*/
JNIEXPORT jdouble JNICALL Java_com_example_packtpub_Store_getDouble(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setDouble
* Signature: (Ljava/lang/String;D)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setDouble(JNIEnv *, jobject, jstring, jdouble);

/**
* Class: com_example_packtpub_Store
* Method: getFloat
* Signature: (Ljava/lang/String;)F
*/
JNIEXPORT jfloat JNICALL Java_com_example_packtpub_Store_getFloat(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setFloat
* Signature: (Ljava/lang/String;F)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setFloat(JNIEnv *, jobject, jstring, jfloat);

/**
* Class: com_example_packtpub_Store
* Method: getInteger
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_example_packtpub_Store_getInteger(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setInteger
* Signature: (Ljava/lang/String;I)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setInteger(JNIEnv *, jobject, jstring, jint);

/**
* Class: com_example_packtpub_Store
* Method: getLong
* Signature: (Ljava/lang/String;)L
*/
JNIEXPORT jlong JNICALL Java_com_example_packtpub_Store_getLong(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setLong
* Signature: (Ljava/lang/String;L)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setLong(JNIEnv *, jobject, jstring, jlong);

/**
* Class: com_example_packtpub_Store
* Method: getShort
* Signature: (Ljava/lang/String;)S
*/
JNIEXPORT jshort JNICALL Java_com_example_packtpub_Store_getShort(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setShort
* Signature: (Ljava/lang/String;S)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setShort(JNIEnv *, jobject, jstring, jshort);

/**
* Class: com_example_packtpub_Store
* Method: getString
* Signature: (Ljava/lang/String;)Ljava/lang/String
*/
JNIEXPORT jstring JNICALL Java_com_example_packtpub_Store_getString(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setString
* Signature: (Ljava/lang/String;Ljava/lang/String)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setString(JNIEnv *, jobject, jstring, jstring);

/**
* Class: com_example_packtpub_Store
* Method: getColor
* Signature: (Ljava/lang/String;)Lcom/packtpub/Color;
*/
JNIEXPORT jobject JNICALL Java_com_example_packtpub_Store_getColor(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setColor
* Signature: (Ljava/lang/String;Lcom/packtpub/Color)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setColor(JNIEnv *, jobject, jstring, jobject);




/**
* Class: com_example_packtpub_Store
* Method: getBooleanArray
* Signature: (Ljava/lang/String;)[Z
*/
JNIEXPORT jbooleanArray JNICALL Java_com_example_packtpub_Store_getBooleanArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setBooleanArray
* Signature: (Ljava/lang/String;[Z)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setBooleanArray(JNIEnv *, jobject, jstring, jbooleanArray);
/**
* Class: com_example_packtpub_Store
* Method: getByteArray
* Signature: (Ljava/lang/String;)[B
*/
JNIEXPORT jbyteArray JNICALL Java_com_example_packtpub_Store_getByteArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setByteArray
* Signature: (Ljava/lang/String;[B)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setByteArray(JNIEnv *, jobject, jstring, jbyteArray);

/**
* Class: com_example_packtpub_Store
* Method: getCharArray
* Signature: (Ljava/lang/String;)[C
*/
JNIEXPORT jcharArray JNICALL Java_com_example_packtpub_Store_getCharArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setCharArray
* Signature: (Ljava/lang/String;[C)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setCharArray(JNIEnv *, jobject, jstring, jcharArray);

/**
* Class: com_example_packtpub_Store
* Method: getDoubleArray
* Signature: (Ljava/lang/String;)[D
*/
JNIEXPORT jdoubleArray JNICALL Java_com_example_packtpub_Store_getDoubleArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setDoubleArray
* Signature: (Ljava/lang/String;[D)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setDoubleArray(JNIEnv *, jobject, jstring, jdoubleArray);

/**
* Class: com_example_packtpub_Store
* Method: getFloatArray
* Signature: (Ljava/lang/String;)[F
*/
JNIEXPORT jfloatArray JNICALL Java_com_example_packtpub_Store_getFloatArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setFloatArray
* Signature: (Ljava/lang/String;[F)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setFloatArray(JNIEnv *, jobject, jstring, jfloatArray);

/**
* Class: com_example_packtpub_Store
* Method: getIntegerArray
* Signature: (Ljava/lang/String;)[I
*/
JNIEXPORT jintArray JNICALL Java_com_example_packtpub_Store_getIntegerArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setIntegerArray
* Signature: (Ljava/lang/String;[I)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setIntegerArray(JNIEnv *, jobject, jstring, jintArray);

/**
* Class: com_example_packtpub_Store
* Method: getLongArray
* Signature: (Ljava/lang/String;)[J
*/
JNIEXPORT jlongArray JNICALL Java_com_example_packtpub_Store_getLongArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setLongArray
* Signature: (Ljava/lang/String;[I)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setLongArray(JNIEnv *, jobject, jstring, jlongArray);

/**
* Class: com_example_packtpub_Store
* Method: getShortArray
* Signature: (Ljava/lang/String;)[S
*/
JNIEXPORT jshortArray JNICALL Java_com_example_packtpub_Store_getShortArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setShortArray
* Signature: (Ljava/lang/String;[S)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setShortArray(JNIEnv *, jobject, jstring, jshortArray);

/**
* Class: com_example_packtpub_Store
* Method: getStringArray
* Signature: (Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_com_example_packtpub_Store_getStringArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setStringArray
* Signature: (Ljava/lang/String;[Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setShortArray(JNIEnv *, jobject, jstring, jobjectArray);

/**
* Class: com_example_packtpub_Store
* Method: getColorArray
* Signature: (Ljava/lang/String;)[Lcom/packtpub/Color;
*/
JNIEXPORT jobjectArray JNICALL Java_com_example_packtpub_Store_getColorArray(JNIEnv *, jobject, jstring);

/**
* Class: com_example_packtpub_Store
* Method: setColorArray
* Signature: (Ljava/lang/String;[Lcom/packtpub/Color;)V
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setColorArray(JNIEnv *, jobject, jstring, jobjectArray);



#ifdef __cplusplus
}
#endif

#endif /* COM_PACKTPUB_STORE_H_ */

这段代码就是对c++环境的处理

<span style="color:#009900;">#ifdef __cplusplus
extern "C" {//这个代码如果要时c++,就把接口强转成c的标准接口
#endif</span>

我们还以第一个函数为例
<pre name="code" class="cpp" style="font-size: 11px;">JNIEXPORT jboolean JNICALL Java_com_example_packtpub_Store_getBoolean(JNIEnv *, jobject, jstring);
JNIEXPORT 和 JNICALL 都是JNI的导出标志,下面我们来看一下函数名的规则: 

Java_com_example_packtpub_Store_getBoolean  Java就是表示语言,基本固定不变,下面是包的名字com.example.packtpub,紧跟着是类名Store,

最后函数名getBoolean,中间全部用下划线分开。

参数(JNIEnv *, jobject,jstring),可以看到,从java那边传过来只有jsting一个参数,另外两个都是JNI默认传过来的。即使,java中是void函数,在c中也是

有JNIEnv*和jobject 这两个参数。JNIEnv*是JVM中的指针,另外,一个我也不清楚。希望知道的朋友可以告诉一下,谢谢!

下面,看以下c中的具体实现,代码如下

/*
* com_packtpub_Store.c
*
* Created on: May 18, 2015
* Author: Lioncraft
*/

#include "com_packtpub_Store.h"
#include <stdint.h>
#include <string.h>
#include "Store.h"

/**
* Contains the unique store instance in a static variable created
* when library is loaded.
*/
static Store mStore = {{}, 0};

/**
* Initialization/Finialization.
*/
JNIEXPORT void JNICALL Java_com_example_packtpub_Store_initializeStore(JNIEnv *pEnv, jobject pThis)
{
mStore.mLength = 0;
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_finalizeStore(JNIEnv *pEnv, jobject pThis)
{
StoreEntry* lEntry = mStore.mEntries;
StoreEntry* lEntryEnd = lEntry + mStore.mLength;


// Releases every entry in the store.
while (lEntry < lEntryEnd) {
free(lEntry->mKey);
releaseEntryValue(pEnv, lEntry);

++lEntry;
}
mStore.mLength = 0;
}

/*
* Getter/setter on primitives and objects.
*/
JNIEXPORT jboolean JNICALL Java_com_example_packtpub_Store_getBoolean(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Boolean)) {
return lEntry->mValue.mBoolean;
} else {
return 0;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setBoolean(JNIEnv *pEnv, jobject pThis, jstring pKey, jboolean pBoolean)
{
// Creates a new entry (or finds it if it already exists) in the
// store.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
// Updates entry content with the requested data.
lEntry->mType = StoreType_Boolean;
lEntry->mValue.mBoolean = pBoolean;
}
}

JNIEXPORT jbyte JNICALL Java_com_example_packtpub_Store_getByte(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Byte)) {
return lEntry->mValue.mByte;
} else {
return 0;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setByte(JNIEnv *pEnv, jobject pThis, jstring pKey, jbyte pByte)
{
// Creates a new entry (or finds it if it already exists) in the
// store.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
// Updates entry content with the requested data.
lEntry->mType = StoreType_Byte;
lEntry->mValue.mByte = pByte;
}
}

JNIEXPORT jchar JNICALL Java_com_example_packtpub_Store_getChar(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Char)) {
return lEntry->mValue.mChar;
} else {
return 0;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setChar(JNIEnv *pEnv, jobject pThis, jstring pKey, jchar pChar)
{
// Creates a new entry (or finds it if it already exists) in the
// store.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
// Updates entry content with the requested data.
lEntry->mType = StoreType_Char;
lEntry->mValue.mChar = pChar;
}
}

JNIEXPORT jdouble JNICALL Java_com_example_packtpub_Store_getDouble(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Double)) {
return lEntry->mValue.mDouble;
} else {
return 0;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setDouble(JNIEnv *pEnv, jobject pThis, jstring pKey, jdouble pDouble)
{
// Creates a new entry (or finds it if it already exists) in the
// store.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
// Updates entry content with the requested data.
lEntry->mType = StoreType_Double;
lEntry->mValue.mDouble = pDouble;
}
}

JNIEXPORT jfloat JNICALL Java_com_example_packtpub_Store_getFloat(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Float)) {
return lEntry->mValue.mFloat;
} else {
return 0;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setFloat(JNIEnv *pEnv, jobject pThis, jstring pKey, jfloat pFloat)
{
// Creates a new entry (or finds it if it already exists) in the
// store.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
// Updates entry content with the requested data.
lEntry->mType = StoreType_Float;
lEntry->mValue.mFloat = pFloat;
}
}

JNIEXPORT jint JNICALL Java_com_example_packtpub_Store_getInteger(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Integer)) {
return lEntry->mValue.mInteger;
} else {
return 0;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setInteger(JNIEnv *pEnv, jobject pThis, jstring pKey, jint pInteger)
{
// Creates a new entry (or finds it if it already exists) in the
// store.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
// Updates entry content with the requested data.
lEntry->mType = StoreType_Integer;
lEntry->mValue.mInteger = pInteger;
}
}

JNIEXPORT jlong JNICALL Java_com_example_packtpub_Store_getLong(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Long)) {
return lEntry->mValue.mLong;
} else {
return 0;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setLong(JNIEnv *pEnv, jobject pThis, jstring pKey, jlong pLong)
{
// Creates a new entry (or finds it if it already exists) in the
// store.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
// Updates entry content with the requested data.
lEntry->mType = StoreType_Long;
lEntry->mValue.mLong = pLong;
}
}

JNIEXPORT jshort JNICALL Java_com_example_packtpub_Store_getShort(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Short)) {
return lEntry->mValue.mShort;
} else {
return 0;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setShort(JNIEnv *pEnv, jobject pThis, jstring pKey, jshort pShort)
{
// Creates a new entry (or finds it if it already exists) in the
// store.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
// Updates entry content with the requested data.
lEntry->mType = StoreType_Short;
lEntry->mValue.mShort = pShort;
}
}

JNIEXPORT jstring JNICALL Java_com_example_packtpub_Store_getString(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_String)) {
//// Converts a C string into a Java String.
return (*pEnv)->NewStringUTF(pEnv, lEntry->mValue.mString);
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setString(JNIEnv *pEnv, jobject pThis, jstring pKey, jstring pString)
{
// Turns the Java string into a temporary C string.
// GetStringUTFChars() is used here as an example but
// Here, GetStringUTFChars() to show
// the way it works. But as what we want is only a copy,
// GetBooleanArrayRegion() would be be more efficient.
const char* lStringTmp = (*pEnv)->GetStringUTFChars(pEnv, pString, NULL);
if (lStringTmp == NULL) {
return;
}
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {

lEntry->mType = StoreType_String;
// Copy the temporary C string into its dynamically allocated
// final location. Then releases the temporary string.
// Malloc return value should theoretically be checked...
jsize lStringLength = (*pEnv)->GetStringUTFLength(pEnv, pString);
lEntry->mValue.mString = (char*) malloc(sizeof(char) * (lStringLength + 1));
strcpy(lEntry->mValue.mString, lStringTmp);
}
}

JNIEXPORT jobject JNICALL Java_com_example_packtpub_Store_getColor(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Color)) {
// Returns a Java object.
return lEntry->mValue.mColor;
} else {
return NULL;
}

}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setColor(JNIEnv *pEnv, jobject pThis, jstring pKey, jobject pColor)
{
// The Java Color is going to be stored on the native side.
// Need to keep a global reference to avoid a potential
// garbage collection after method returns.
jobject lColor = (*pEnv)->NewGlobalRef(pEnv, pColor);
if (lColor == NULL) {
return;
}

// Save the Color reference in the store.
StoreEntry * lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
lEntry->mType = StoreType_Color;
lEntry->mValue.mColor = lColor;
} else {
(*pEnv)->DeleteGlobalRef(pEnv, lColor);
}
}

/*
* Getter/setter on arrays.
*/

JNIEXPORT jbooleanArray JNICALL Java_com_example_packtpub_Store_getBooleanArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_BooleanArray)) {
jbooleanArray lJavaArray = (*pEnv)->NewBooleanArray(pEnv, lEntry->mLength);

if (lJavaArray == NULL) {
return NULL;
}

(*pEnv)->SetBooleanArrayRegion(pEnv, lJavaArray, 0, lEntry->mLength, lEntry->mValue.mBooleanArray);

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setBooleanArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jbooleanArray pBooleanArray)
{
// Retrieves array content. Here, Get<Primitive>ArrayElements()
// is used to show the way it works. But as what we want is only
// a copy, GetBooleanArrayRegion() would be be more efficient.

jboolean* lArrayTmp = (*pEnv)->GetBooleanArrayElements(pEnv, pBooleanArray, NULL);
if (lArrayTmp == NULL) {
return ;
}

// Finds/creates an entry in the store and fills its content.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_BooleanArray;
// Allocates a new C buffer which is going to hold a copy of
// the Java array.
lEntry->mLength = (*pEnv)->GetArrayLength(pEnv, pBooleanArray);
size_t lBufferLength = lEntry->mLength * sizeof(uint8_t);
//Malloc return value should theoretically be checked...
lEntry->mValue.mBooleanArray = (uint8_t*) malloc(lBufferLength);
memcpy(lEntry->mValue.mBooleanArray, lArrayTmp, lBufferLength);
}

// We have performed any modification on the array and thus do
// not plan to send any modified data back to Java. So uses
// JNI_ABORT flag for efficiency purpose.
(*pEnv)->ReleaseBooleanArrayElements(pEnv, pBooleanArray, lArrayTmp, JNI_ABORT);
}

JNIEXPORT jbyteArray JNICALL Java_com_example_packtpub_Store_getByteArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_ByteArray)) {
jbyteArray lJavaArray = (*pEnv)->NewByteArray(pEnv, lEntry->mLength);

if (lJavaArray == NULL) {
return NULL;
}

(*pEnv)->SetByteArrayRegion(pEnv, lJavaArray, 0, lEntry->mLength, lEntry->mValue.mByteArray);

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setByteArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jbyteArray pByteArray)
{
// Allocates a C array with the same size as the Java array.
jsize lLength = (*pEnv)->GetArrayLength(pEnv, pByteArray);
int8_t* lArray = (int8_t*) malloc(lLength * sizeof(int8_t));
// Copies Java array content directly in this new C array.
(*pEnv)->GetByteArrayRegion(pEnv, pByteArray, 0, lLength, lArray);

// GetByteArrayRegion() does not return a value. Thus exceptions
// need to be checked explicitely (here, an IndexOutOfBound
// could theoretically occur).
if ((*pEnv)->ExceptionCheck(pEnv)) {
free(lArray);
return;
}

// Creates a new store entry containing the C array.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_ByteArray;
lEntry->mLength = lLength;
lEntry->mValue.mByteArray = lArray;
} else {
// If an error occurs, releases what has been allocated.
free(lArray);
return;
}
}

JNIEXPORT jcharArray JNICALL Java_com_example_packtpub_Store_getCharArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_CharArray)) {
jcharArray lJavaArray = (*pEnv)->NewCharArray(pEnv, lEntry->mLength);

if (lJavaArray == NULL) {
return NULL;
}

(*pEnv)->SetCharArrayRegion(pEnv, lJavaArray, 0, lEntry->mLength, lEntry->mValue.mCharArray);

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setCharArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jcharArray pCharArray)
{
// Allocates a C array with the same size as the Java array.
jsize lLength = (*pEnv)->GetArrayLength(pEnv, pCharArray);
int16_t* lArray = (int16_t*) malloc(lLength * sizeof(int16_t));
// Copies Java array content directly in this new C array.
(*pEnv)->GetByteArrayRegion(pEnv, pCharArray, 0, lLength, lArray);

// GetByteArrayRegion() does not return a value. Thus exceptions
// need to be checked explicitely (here, an IndexOutOfBound
// could theoretically occur).
if ((*pEnv)->ExceptionCheck(pEnv)) {
free(lArray);
return;
}

// Creates a new store entry containing the C array.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_CharArray;
lEntry->mLength = lLength;
lEntry->mValue.mCharArray = lArray;
} else {
// If an error occurs, releases what has been allocated.
free(lArray);
return;
}
}

JNIEXPORT jdoubleArray JNICALL Java_com_example_packtpub_Store_getDoubleArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_DoubleArray)) {
jdoubleArray lJavaArray = (*pEnv)->NewDoubleArray(pEnv, lEntry->mLength);

if (lJavaArray == NULL) {
return NULL;
}

(*pEnv)->SetDoubleArrayRegion(pEnv, lJavaArray, 0, lEntry->mLength, lEntry->mValue.mDoubleArray);

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setDoubleArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jdoubleArray pDoubleArray)
{
// Allocates a C array with the same size as the Java array.
jsize lLength = (*pEnv)->GetArrayLength(pEnv, pDoubleArray);
double* lArray = (double*) malloc(lLength * sizeof(double));
// Copies Java array content directly in this new C array.
(*pEnv)->GetDoubleArrayRegion(pEnv, pDoubleArray, 0, lLength, lArray);

// GetByteArrayRegion() does not return a value. Thus exceptions
// need to be checked explicitely (here, an IndexOutOfBound
// could theoretically occur).
if ((*pEnv)->ExceptionCheck(pEnv)) {
free(lArray);
return;
}

// Creates a new store entry containing the C array.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_DoubleArray;
lEntry->mLength = lLength;
lEntry->mValue.mDoubleArray = lArray;
} else {
// If an error occurs, releases what has been allocated.
free(lArray);
return;
}
}

JNIEXPORT jfloatArray JNICALL Java_com_example_packtpub_Store_getFloatArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_FloatArray)) {
jfloatArray lJavaArray = (*pEnv)->NewFloatArray(pEnv, lEntry->mLength);

if (lJavaArray == NULL) {
return NULL;
}

(*pEnv)->SetFloatArrayRegion(pEnv, lJavaArray, 0, lEntry->mLength, lEntry->mValue.mFloatArray);

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setFloatArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jfloatArray pFloatArray)
{
// Allocates a C array with the same size as the Java array.
jsize lLength = (*pEnv)->GetArrayLength(pEnv, pFloatArray);
float* lArray = (float*) malloc(lLength * sizeof(float));
// Copies Java array content directly in this new C array.
(*pEnv)->GetFloatArrayRegion(pEnv, pFloatArray, 0, lLength, lArray);

// GetByteArrayRegion() does not return a value. Thus exceptions
// need to be checked explicitely (here, an IndexOutOfBound
// could theoretically occur).
if ((*pEnv)->ExceptionCheck(pEnv)) {
free(lArray);
return;
}

// Creates a new store entry containing the C array.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_FloatArray;
lEntry->mLength = lLength;
lEntry->mValue.mFloatArray = lArray;
} else {
// If an error occurs, releases what has been allocated.
free(lArray);
return;
}
}

JNIEXPORT jintArray JNICALL Java_com_example_packtpub_Store_getIntegerArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_IntegerArray)) {
jintArray lJavaArray = (*pEnv)->NewIntArray(pEnv, lEntry->mLength);

if (lJavaArray == NULL) {
return NULL;
}

(*pEnv)->SetIntArrayRegion(pEnv, lJavaArray, 0, lEntry->mLength, lEntry->mValue.mIntegerArray);

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setIntegerArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jintArray pIntegerArray)
{
// Allocates a C array with the same size as the Java array.
jsize lLength = (*pEnv)->GetArrayLength(pEnv, pIntegerArray);
int32_t* lArray = (int32_t*) malloc(lLength * sizeof(int32_t));
// Copies Java array content directly in this new C array.
(*pEnv)->GetIntArrayRegion(pEnv, pIntegerArray, 0, lLength, lArray);

// GetByteArrayRegion() does not return a value. Thus exceptions
// need to be checked explicitely (here, an IndexOutOfBound
// could theoretically occur).
if ((*pEnv)->ExceptionCheck(pEnv)) {
free(lArray);
return;
}

// Creates a new store entry containing the C array.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_IntegerArray;
lEntry->mLength = lLength;
lEntry->mValue.mIntegerArray = lArray;
} else {
// If an error occurs, releases what has been allocated.
free(lArray);
return;
}
}


JNIEXPORT jlongArray JNICALL Java_com_example_packtpub_Store_getLongArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_LongArray)) {
jlongArray lJavaArray = (*pEnv)->NewLongArray(pEnv, lEntry->mLength);

if (lJavaArray == NULL) {
return NULL;
}

(*pEnv)->SetLongArrayRegion(pEnv, lJavaArray, 0, lEntry->mLength, lEntry->mValue.mLongArray);

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setLongArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jlongArray pLongArray)
{
// Allocates a C array with the same size as the Java array.
jsize lLength = (*pEnv)->GetArrayLength(pEnv, pLongArray);
int64_t* lArray = (int64_t*) malloc(lLength * sizeof(int64_t));
// Copies Java array content directly in this new C array.
(*pEnv)->GetIntArrayRegion(pEnv, pLongArray, 0, lLength, lArray);

// GetByteArrayRegion() does not return a value. Thus exceptions
// need to be checked explicitely (here, an IndexOutOfBound
// could theoretically occur).
if ((*pEnv)->ExceptionCheck(pEnv)) {
free(lArray);
return;
}

// Creates a new store entry containing the C array.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_LongArray;
lEntry->mLength = lLength;
lEntry->mValue.mLongArray = lArray;
} else {
// If an error occurs, releases what has been allocated.
free(lArray);
return;
}
}


JNIEXPORT jshortArray JNICALL Java_com_example_packtpub_Store_getShortArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_ShortArray)) {
jshortArray lJavaArray = (*pEnv)->NewShortArray(pEnv, lEntry->mLength);

if (lJavaArray == NULL) {
return NULL;
}

(*pEnv)->SetShortArrayRegion(pEnv, lJavaArray, 0, lEntry->mLength, lEntry->mValue.mShortArray);

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setShortArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jshortArray pShortArray)
{
// Allocates a C array with the same size as the Java array.
jsize lLength = (*pEnv)->GetArrayLength(pEnv, pShortArray);
int16_t* lArray = (int16_t*) malloc(lLength * sizeof(int16_t));
// Copies Java array content directly in this new C array.
(*pEnv)->GetIntArrayRegion(pEnv, pShortArray, 0, lLength, lArray);

// GetByteArrayRegion() does not return a value. Thus exceptions
// need to be checked explicitely (here, an IndexOutOfBound
// could theoretically occur).
if ((*pEnv)->ExceptionCheck(pEnv)) {
free(lArray);
return;
}

// Creates a new store entry containing the C array.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_ShortArray;
lEntry->mLength = lLength;
lEntry->mValue.mShortArray = lArray;
} else {
// If an error occurs, releases what has been allocated.
free(lArray);
return;
}
}


JNIEXPORT jobjectArray JNICALL Java_com_example_packtpub_Store_getStringArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_StringArray)) {
// An array of String in Java is in fact an array of object.
jclass lStringClass = (*pEnv)->FindClass(pEnv, "java/lang/String");
if (lStringClass == NULL) {
return NULL;
}
jobjectArray lJavaArray = (*pEnv)->NewObjectArray(pEnv, lEntry->mLength, lStringClass, NULL);

if (lJavaArray == NULL) {
return NULL;
}

// Creates a new Java String object for each C string stored.
// Reference to the String can be removed right after it is
// added to the Java array, as the latter holds a reference
// to the String object.
int32_t i;
for (i = 0; i < lEntry->mLength; ++i) {
jstring lString = (*pEnv)->NewStringUTF(pEnv, lEntry->mValue.mStringArray[i]);
if (lString == NULL) {
return NULL;
}

// Puts the new string in the array. Exception are
// checked because of SetObjectArrayElement() (can raise
// an ArrayIndexOutOfBounds or ArrayStore Exception).
// If one occurs, any object created here will be freed
// as they are all referenced locally only.
(*pEnv)->SetObjectArrayElement(pEnv, lJavaArray, i, lString);
// Note that DeleteLocalRef() can still be called safely
// even if an exception is raised.
(*pEnv)->DeleteLocalRef(pEnv, lString);
if ((*pEnv)->ExceptionCheck(pEnv)) {
return NULL;
}
}

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setStringArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jobjectArray pStringArray)
{
// Allocates a C array with the same size as the Java array.
jsize lLength = (*pEnv)->GetArrayLength(pEnv, pStringArray);
char** lArray = (char**) malloc(lLength * sizeof(char*));

// Fills the C array with a copy of each input Java string.
int32_t i,j;
for (i = 0; i < lLength; ++i) {
// Gets the current Java String from the input Java array.
// Object arrays can be accessed element by element only.
jstring lString = (*pEnv)->GetObjectArrayElement(pEnv, pStringArray, i);
if ((*pEnv)->ExceptionCheck(pEnv)) {
for (j = 0; j < i; ++j) {
free(lArray[j]);
}
free(lArray);
return;
}

jsize lStringLength = (*pEnv)->GetStringUTFLength(pEnv, lString);
// Malloc return value should theoretically be checked...
lArray[i] = (char*) malloc(sizeof(char) * (lStringLength + 1));
// Directly copies the Java String into our new C buffer.
// This is usually faster than GetStringUTFChars() which
// requires copying manually.
(*pEnv)->GetStringUTFRegion(pEnv, lString, 0, lStringLength, lArray[i]);
if ((*pEnv)->ExceptionCheck(pEnv)) {
for (j = 0; j < i; ++j) {
free(lArray[j]);
}
free(lArray);
return;
}
// No need to keep a reference to the Java string anymore.
(*pEnv)->DeleteLocalRef(pEnv, lString);

}

// Creates a new entry with the new String array.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_StringArray;
lEntry->mLength = lLength;
lEntry->mValue.mStringArray = lArray;
} else {
// If an error occurs, releases what has been allocated.
for (j = 0; j < lLength; ++j) {
free(lArray[j]);
}
free(lArray);
return;
}
}

JNIEXPORT jobjectArray JNICALL Java_com_example_packtpub_Store_getColorArray(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_ColorArray)) {
// Creates a new array with objects of type Id.
jclass lColorClass = (*pEnv)->FindClass(pEnv, "com/example/packtpub/Color");
if (lColorClass == NULL) {
return NULL;
}
jobjectArray lJavaArray = (*pEnv)->NewObjectArray(pEnv, lEntry->mLength, lColorClass, NULL);

if (lJavaArray == NULL) {
return NULL;
}

// Fills the array with the Color objects stored on the native
// side, which keeps a global reference to them. So no need
// to delete or create any reference here.
int32_t i;
for (i = 0; i < lEntry->mLength; ++i) {

(*pEnv)->SetObjectArrayElement(pEnv, lJavaArray, i, lEntry->mValue.mColorArray[i]);

if ((*pEnv)->ExceptionCheck(pEnv)) {
return NULL;
}
}

return lJavaArray;
} else {
return NULL;
}
}

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setColorArray(JNIEnv *pEnv, jobject pThis, jstring pKey, jobjectArray pColorArray)
{
// Allocates a C array with the same size as the Java array.
jsize lLength = (*pEnv)->GetArrayLength(pEnv, pColorArray);
jobject* lArray = (jobject*) malloc(lLength * sizeof(jobject));

// Fills the C array with a copy of each input Java object.
int32_t i,j;
for (i = 0; i < lLength; ++i) {
// Gets the current Java Color from the input Java array.
// Object arrays can be accessed element by element only.
jobject llocalColor = (*pEnv)->GetObjectArrayElement(pEnv, pColorArray, i);
if (NULL == llocalColor) {
for (j = 0; j < i; ++j) {
(*pEnv)->DeleteGlobalRef(pEnv, lArray[j]);
}
free(lArray);
return;
}

// The Java Color is going to be stored on the native side.
// Need to keep a global reference to avoid a potential
// garbage collection after method returns.
// Malloc return value should theoretically be checked...
lArray[i] = (*pEnv)->NewGlobalRef(pEnv,llocalColor);

if (NULL == lArray[i]) {
for (j = 0; j < i; ++j) {
(*pEnv)->DeleteGlobalRef(pEnv, lArray[j]);
}
free(lArray);
return;
}
// We have a global reference to the Color, so we can now get
// rid of the local one.
(*pEnv)->DeleteLocalRef(pEnv, llocalColor);

}

// Creates a new entry with the new String array.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);

if (lEntry != NULL) {
lEntry->mType = StoreType_ColorArray;
lEntry->mLength = lLength;
lEntry->mValue.mColorArray = lArray;
} else {
// If an exception happens, global references must be
// carefully destroyed or objects will never get garbage
// collected (as we finally decide not to store them).
for (j = 0; j < i; ++j) {
(*pEnv)->DeleteGlobalRef(pEnv, lArray[j]);
}
free(lArray);
return;
}
}

我们来看一下getBoolean是怎么获得值的

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Boolean)) {
return lEntry->mValue.mBoolean;
} else {
return 0;
}
StoreEntry 是一个结构体,里面存储被保存的信息,findEntry查找存储中是否有要找的值,有就返回,没有就返回0;

再来看一下是怎么设置值。以setBoolean为例

// Creates a new entry (or finds it if it already exists) in the
// store.
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
// Updates entry content with the requested data.
lEntry->mType = StoreType_Boolean;
lEntry->mValue.mBoolean = pBoolean;
}

我们要新生成一个StoreEntry对象,把传过的类型,和值存储再StoreEntry中。

下面,再看两个特殊的类型传递,一个是String,一个是对象。

getString

JNIEXPORT jstring JNICALL Java_com_example_packtpub_Store_getString(JNIEnv *pEnv, jobject pThis, jstring pKey)
{
StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_String)) {
//// Converts a C string into a Java String.
return (*pEnv)->NewStringUTF(pEnv, lEntry->mValue.mString);
} else {
return NULL;
}
}
注意这里返回的时候用到了NewStringUTF函数,简单的说是把,c中的字符串转化为java中的字符串。

setString

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setString(JNIEnv *pEnv, jobject pThis, jstring pKey, jstring pString)
{
// Turns the Java string into a temporary C string.
// GetStringUTFChars() is used here as an example but
// Here, GetStringUTFChars() to show
// the way it works. But as what we want is only a copy,
// GetBooleanArrayRegion() would be be more efficient.
const char* lStringTmp = (*pEnv)->GetStringUTFChars(pEnv, pString, NULL);
if (lStringTmp == NULL) {
return;
}
StoreEntry* lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {

lEntry->mType = StoreType_String;
// Copy the temporary C string into its dynamically allocated
// final location. Then releases the temporary string.
// Malloc return value should theoretically be checked...
jsize lStringLength = (*pEnv)->GetStringUTFLength(pEnv, pString);
lEntry->mValue.mString = (char*) malloc(sizeof(char) * (lStringLength + 1));
strcpy(lEntry->mValue.mString, lStringTmp);
}
}

把JNI中的jstring转成c 的字符串

const char* lStringTmp = (*pEnv)->GetStringUTFChars(pEnv, pString, NULL);
判断jstring数组长度,
<pre name="code" class="cpp">jsize lStringLength = (*pEnv)->GetStringUTFLength(pEnv, pString);

 

并在c中new 一个同样的大小的数组,把他给拷贝过去。

lEntry->mValue.mString = (char*) malloc(sizeof(char) * (lStringLength + 1));
strcpy(lEntry->mValue.mString, lStringTmp);

对象的也相对简单直接返回jobject对象

JNIEXPORT jobject JNICALL Java_com_example_packtpub_Store_getColor(JNIEnv *pEnv, jobject pThis, jstring pKey)
{

StoreEntry* lEntry = findEntry(pEnv, &mStore, pKey, NULL);
if (isEntryValid(pEnv, lEntry, StoreType_Color)) {
// Returns a Java object.
return lEntry->mValue.mColor;
} else {
return NULL;
}

}
再设置对象的时候

JNIEXPORT void JNICALL Java_com_example_packtpub_Store_setColor(JNIEnv *pEnv, jobject pThis, jstring pKey, jobject pColor)
{
// The Java Color is going to be stored on the native side.
// Need to keep a global reference to avoid a potential
// garbage collection after method returns.
jobject lColor = (*pEnv)->NewGlobalRef(pEnv, pColor);
if (lColor == NULL) {
return;
}

// Save the Color reference in the store.
StoreEntry * lEntry = allocateEntry(pEnv, &mStore, pKey);
if (lEntry != NULL) {
lEntry->mType = StoreType_Color;
lEntry->mValue.mColor = lColor;
} else {
(*pEnv)->DeleteGlobalRef(pEnv, lColor);
}
}
先用函数NewGlobalRef把对象转换成C中可识别的jobject。实质上就是再c中new 一个jobject对象, 再无法赋值的时候要用DeleteGlobalRef释放。

数组的传递,有代码。大家可以自己看。完整的demo最后,会给出。

下面类看一下,c中是怎么调java中的内容。下面是一个Java的异常类。

package com.example.exception;

@SuppressWarnings("serial")
public class InvalidTypeException extends Exception{

public InvalidTypeException() {
super();
}

public InvalidTypeException(String strDetailMessage, Throwable throwable) {
super(strDetailMessage, throwable);
}

public InvalidTypeException(String strDetailMessage) {
super(strDetailMessage);
}

public InvalidTypeException(Throwable throwable) {
super(throwable);
}
}

在c中使用如下代码就可调用

void throwInvalidTypeException(JNIEnv* pEnv)
{
jclass lClass = (*pEnv)->FindClass(pEnv,
"com/example/exception/InvalidTypeException");
if (NULL != lClass) {
(*pEnv)->ThrowNew(pEnv, lClass, "Type is invalid.");
}
(*pEnv)->DeleteLocalRef(pEnv, lClass);
}
FindClass 的后一个参数就是包的名加上类的名称。

然后调用ThrowNew函数把对用的值传入java中的构造函数。

最后,释放类的引用。



下面给出完整的demo,https://github.com/lishihaojie/NDK/tree/master/ndk1/MyNDK