* AndroidのNDK JNIのディレクトリエントリのメモ*
JavaとJNI参照データ型
Javaオブジェクトの異なるタイプに対応し、JNI参照型は、多数の含有します
Javaクラス・タイプ | JNI参照型 | タイプ説明 |
---|---|---|
java.lang.Object上位 | jオブジェクト | 任意のJavaオブジェクトを表す、またはJavaのは対応するタイプが存在しなくてもよいことはJNIオブジェクト(メソッドの必須パラメータの例) |
java.lang.Stringで | JSTRING | Javaは、String型の文字列の対象であります |
java.lang.Class | JCLASS | オブジェクトのJavaのクラスタイプ(必須パラメータ静的メソッド) |
オブジェクト[] | jobjectArray | 任意のJavaオブジェクトの配列表現 |
ブール[] | jbooleanArray | Javaプリミティブ型boolean型配列表現 |
バイト[] | jbyteArray | Javaプリミティブ型byteの配列表現 |
CHAR [] | jcharArray | Javaのプリミティブ型charの配列表現 |
ショート[] | jshortArray | Javaのプリミティブ型のショートの配列表現 |
INT [] | jintArray | Javaのプリミティブ型intの配列表現 |
長いです[] | jlongArray | Javaのプリミティブ型の配列表現長いです |
浮く[] | jfloatArray | Javaのプリミティブ型floatの配列表現 |
ダブル[] | jdoubleArray | Javaのプリミティブ型の二重の配列表現 |
java.lang.Throwableの | jthrowable | JavaのタイプのThrowableは、すべてのタイプと異常サブカテゴリを表します |
基本データ型配列のJNI参照型-Java
JNI配列操作を感じるためにいくつかの例を書きます。
ネイティブ、Java形式から配列を取得します
/**
* 从 Native 获取数组,Java 进行格式化
* @param view
*/
public void getNativeArray(View view) {
boolean[] nativeArray = NativeUtil.getNativeArray();
StringBuilder stringBuilder = new StringBuilder("[");
for(int i = 0; i < nativeArray.length; i++) {
stringBuilder.append(nativeArray[i]);
if(i != nativeArray.length -1) {
stringBuilder.append(", ");
}
}
stringBuilder.append("]");
getNativeArrayText.setText(stringBuilder.toString());
}
// JNI 对数组的操作
extern "C"
JNIEXPORT jbooleanArray JNICALL
Java_com_ihubin_ndkjni_NativeUtil_getNativeArray(JNIEnv *env, jclass clazz) {
jboolean* jb = new jboolean[5];
jb[0] = JNI_TRUE;
jb[1] = JNI_FALSE;
jb[2] = JNI_TRUE;
jb[3] = JNI_FALSE;
jb[4] = JNI_TRUE;
jbooleanArray jba = env->NewBooleanArray(5);
env->SetBooleanArrayRegion(jba, 0, 5, jb);
return jba;
}
Java配列は、ネイティブフォーマットをネイティブに合格しました
/**
* 将 Java 数组传入 Native,Native 格式化
* @param view
*/
public void formatArray(View view) {
int[] intArray = {11, 22, 33, 44, 55};
String formatArrayStr = NativeUtil.formatArray(intArray);
formatArrayText.setText(formatArrayStr);
}
// JNI 对数组的操作
Java_com_ihubin_ndkjni_NativeUtil_formatArray(JNIEnv *env, jclass clazz, jintArray int_array) {
jint array[5];
env->GetIntArrayRegion(int_array, 0, 5, array);
jsize size = env->GetArrayLength(int_array);
char resutStr[100] = {0};
char str[10] = {0};
strcat(resutStr, "[");
for(int i = 0; i < size; i++) {
sprintf(str, "%d", array[i]);
strcat(resutStr, str);
if(i != size - 1) {
strcat(resutStr, ", ");
}
}
strcat(resutStr, "]");
return env->NewStringUTF(resutStr);
}
商品の合計金額を計算するためにネイティブ
/**
* Native 计算商品总价
* @param view
*/
public void calcTotalMoney(View view) {
double[] price = {5.5, 6.6, 7.7, 8.8, 9.9};
String resultStr = NativeUtil.calcTotalMoney(price);
calcTotalMoneyText.setText(resultStr);
}
// JNI 对数组的操作
extern "C"
JNIEXPORT jstring JNICALL
Java_com_ihubin_ndkjni_NativeUtil_calcTotalMoney(JNIEnv *env, jclass clazz, jdoubleArray price) {
jdouble array[5];
env->GetDoubleArrayRegion(price, 0, 5, array);
jsize size = env->GetArrayLength(price);
char resutStr[255] = {0};
char str[20] = {0};
strcat(resutStr, "sum(");
jdouble totalMoney = 0.0;
for(int i = 0; i < size; i++) {
sprintf(str, "%.1f", array[i]);
strcat(resutStr, str);
if(i != size - 1) {
strcat(resutStr, ", ");
}
totalMoney += array[i];
}
strcat(resutStr, ")");
strcat(resutStr, "\n=");
sprintf(str, "%.1f", totalMoney);
strcat(resutStr, str);
return env->NewStringUTF(resutStr);
}
介してすべての被験者かどうかを計算するためにネイティブ
/**
* 计算各科成绩是否通过
* @param view
*/
public void calcScorePass(View view) {
float[] yourScore = {59.0F, 88.0F, 76.5F, 45.0F, 98.0F};
String[] yourScoreResult = NativeUtil.calcScorePass(yourScore);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
for(int i = 0; i < yourScore.length; i++) {
stringBuilder.append(yourScore[i]);
if(i != yourScore.length - 1) {
stringBuilder.append(", ");
}
}
stringBuilder.append("]");
stringBuilder.append("\n");
stringBuilder.append("[");
for(int i = 0; i < yourScoreResult.length; i++) {
stringBuilder.append(yourScoreResult[i]);
if(i != yourScoreResult.length - 1) {
stringBuilder.append(", ");
}
}
stringBuilder.append("]");
calcScorePassText.setText(stringBuilder.toString());
}
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_com_ihubin_ndkjni_NativeUtil_calcScorePass(JNIEnv *env, jclass clazz, jfloatArray your_score) {
jfloat array[5];
env->GetFloatArrayRegion(your_score, 0, 5, array);
jsize size = env->GetArrayLength(your_score);
jclass objClass = env->FindClass("java/lang/String");
jobjectArray objArray = env->NewObjectArray(5, objClass, 0);
jstring jstr;
for(int i = 0; i < size; i++) {
if(array[i] >= 60.0) {
jstr = env->NewStringUTF("√");
} else {
jstr = env->NewStringUTF("×");
}
env->SetObjectArrayElement(objArray, i, jstr);
}
return objArray;
}
結果を見てください:
ここでは、配列のデータ型に基本的なJava JNIさまざまな操作を「習得」しています。
で
Native 计算各科成绩是否通过
、この例では、コードがあったjclass objClass = env->FindClass("java/lang/String");
探検するここで。
JNI参照型-Javaオブジェクト
Javaネイティブのすべてのメソッド呼び出し、前に、今、抗ネイティブコードは、Java層を呼び出すコードです。
クラス/プロパティとメソッド/オブジェクト
まず、アクセスClassオブジェクト
jni.h中のヘッダファイルにC / C ++でJavaクラスに呼び出すことができるようにするためには、Javaクラスのクラスの特殊なタイプJCLASS表現を定義します。JCLASSを取得するには、3つのJNIEnvの機能があります。
// 通过类的名称(类的全名,这时候包名不是用'"."点号而是用"/"来区分的)来获取 jclass
jclass FindClass(const char* clsName)
// 通过对象实例来获取 jclass,相当于 Java 中的 getClass() 函数
jclass GetObjectClass(jobject obj)
// 通过 jclass 可以获取其父类的 jclass 对象
jclass getSuperClass(jclass obj)
例:
// 获取 Java 中的类 java.lang.String
jclass objClass = env->FindClass("java/lang/String");
// 获取一个类的父类
jclass superClass = env->getSuperClass(objClass);
第二に、プロパティのgetメソッド
C / C、JNI jfieldIDでと定義で++取得するJava層のプロパティとメソッド二つのタイプは、Javaプロパティとメソッドの終わりを表すためにjni.h中ヘッダーファイルをjmethodIDで。
// 获取属性
jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
// 获取方法
jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
// 获取静态属性
jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig)
// 获取静态方法
jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig)
例:
package com.ihubin.ndkjni;
public class User {
public static int staticField = 88;
public int normalField = 99;
public static String getStaticUserInfo() {
return "[name:hubin, age:18]";
}
public String getNormalUserInfo() {
return "[name:hubin, age:28]";
}
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getFormatInfo() {
return String.format("[name:%s, age:%d]", name, age);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// 获取 jclass
jclass userClass = env->FindClass("com/ihubin/ndkjni/User");
// 获取属性 ID
jfieldID normalField = env->GetFieldID(userClass, "normalField", "I");
// 获取静态属性 ID
jfieldID staticField = env->GetStaticFieldID(userClass, "staticField", "I");
// 获取方法 ID
jmethodID normalMethod = env->GetMethodID(userClass, "getNormalUserInfo", "()Ljava/lang/String;");
// 获取静态方法 ID
jmethodID staticMethod = env->GetStaticMethodID(userClass, "getStaticUserInfo", "()Ljava/lang/String;");
// 获取无参构造函数
jmethodID voidInitMethod = env->GetMethodID(userClass, "<init>", "()V");
// 获取有参构造函数
jmethodID paramInitMethod = env->GetMethodID(userClass, "<init>", "(Ljava/lang/String;I)V");
第三には、オブジェクトを構築します
上記目的により得られたJCLASS以下のクラス属性、メソッド、その後の非静的インスタンスの内部にアクセスするための機能jmethodIDでするように構成され、構成されています。
// 通过 clazz/methodID/...(可变参数列表) 创建一个对象
jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);
// args(参数数组)
jobject NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args);
// args(指向变参列表的指针)
jobject NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args);
// 通过一个类创建一个对象,默认构造函数
jobject AllocObject(JNIEnv *env, jclass clazz)
例:
// 通过无参构造函数
jobject userOne = env->NewObject(userClass, voidInitMethod);
// 通过有参构造函数
jstring name = env->NewStringUTF("HUBIN");
jint age = 8;
jobject userTwo = env->NewObject(userClass, paramInitMethod, name, age);
// 默认构造函数
jobject userThree = env->AllocObject(userClass);
第四に、取得プロパティ、メソッドを呼び出します
前準備は、Javaオブジェクトのプロパティとメソッドを使用できるようにすることです。
プロパティ値を設定、取得します。
XXX Get<type>Field(jobject obj, jfieldID fieldID)
Set<type>Field(jobject obj, jfieldID fieldID, XXX value)
静的プロパティ値を取得設定します。
XXX GetStatic<type>Field(jclass clazz, jfieldID fieldID)
SetStatic<type>Field(jclass clazz, jfieldID fieldID, XXX value)
メソッドを呼び出します。
NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...)
NativeType Call<type>MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args)
NativeType Call<type>MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)
静的メソッドを呼び出します。
NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz, jmethodID methodID, ...)
NativeType CallStatic<type>MethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args)
NativeType CallStatic<type>MethodV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)
例:
// 获取对象中的属性
jint normalFieldValue = env->GetIntField(userOne, normalField);
LOGD("normalField: %d", normalFieldValue);
// 获取 class 中静态属性
jint staticFieldValue = env->GetStaticIntField(userClass, staticField);
LOGD("staticField: %d", staticFieldValue);
// 调用对象中的方法
jobject normalMethodResultObj = env->CallObjectMethod(userOne, normalMethod);
jstring normalMethodResult = static_cast<jstring>(normalMethodResultObj);
const char *normalMethodResultNativeString = env->GetStringUTFChars(normalMethodResult, 0);
LOGD("normalMethodResult: %s", normalMethodResultNativeString);
// 调用 class 中的静态方法
jobject staticMethodResultObj = env->CallStaticObjectMethod(userClass, staticMethod);
jstring staticMethodResult = static_cast<jstring>(staticMethodResultObj);
const char *staticMethodResultNativeString = env->GetStringUTFChars(staticMethodResult, 0);
LOGD("staticMethodResult: %s", staticMethodResultNativeString);
// 调用对象中的方法
jobject getFormatInfoMethodResultObj = env->CallObjectMethod(userTwo, getFormatInfoMethod);
jstring getFormatInfoMethodResult = static_cast<jstring>(getFormatInfoMethodResultObj);
const char *getFormatInfoMethodResultNativeString = env->GetStringUTFChars(getFormatInfoMethodResult, 0);
LOGD("getFormatInfoMethodResult: %s", getFormatInfoMethodResultNativeString);
// 测试 jobject AllocObject(JNIEnv *env, jclass clazz) 创建的对象
jobject userThreeMethodResultObj = env->CallObjectMethod(userThree, normalMethod);
jstring userThreeMethodResult = static_cast<jstring>(userThreeMethodResultObj);
const char *userThreeMethodResultNativeString = env->GetStringUTFChars(userThreeMethodResult, 0);
LOGD("userThreeMethodResult: %s", userThreeMethodResultNativeString);
jfieldIDで、jmethodIDで取得する場合、いくつかの奇妙な文字列があった
I
()Ljava/lang/String;
()V
(Ljava/lang/String;I)V
、下記をご覧来ます。
データ型シグネチャ
保存されたデータ型の名前がそうで署名ストアへのタイプではなく、int型、float型の私たちの習慣とを指定されたJVM仮想マシンで。
JNIは、署名のこのタイプを使用しています。
Java型 | 型シグネチャ |
---|---|
int型 | 私 |
長いです | J |
バイト | B |
ショート | S |
CHAR | C |
浮く | F |
ダブル | D |
ブーリアン | とともに |
空隙 | V |
その他の参照型 | L + +クラスのフルネーム。 |
配列 | [ |
方法 | (パラメータ)戻り値 |
例1
Java 类型:java.lang.String
类型签名:Ljava/lang/String;
即一个 Java 类对应的签名,就是 L 加上类的全名,其中 . 要换成 / ,最后不要忘掉末尾的分号。
例2
Java 类型:String[]
类型签名:[Ljava/lang/String;
Java 类型:int[][]
类型签名:[[I
数组就是简单的在类型描述符前加 [ 即可,二维数组就是两个 [ ,以此类推。
例3
Java 方法:long f (int n, String s, int[] arr);
类型签名:(ILjava/lang/String;[I)J
Java 方法:void f ();
类型签名:()V
括号内是每个参数的类型符,括号外就是返回值的类型符。
使用
javap -s <Class>
ビュー署名
これまでのところ、我々はネイティブのAndroidプロジェクトでJavaオブジェクトを操作することを学びました。
コード:
参考文献:
AndroidのJNI学習(3) - Javaとネイティブコール互いに