(四)NDK開發之 java 與C/C++ 程式碼互相呼叫
java 呼叫c/c++ 的方法,很簡單。我們勾選建立支援C/C++ 專案的時候,就已經生成了一個Demo
下面主要介紹,C/C++ 呼叫 java 的方法。
一、訪問 java 成員非靜態成員變數:
JNI 呼叫java非靜態變數的 方法名格式 : Get<Type>Field() 例如 :int 型別引數 GetIntField()
JNI 呼叫java 靜態變數的 方法名格式 : GetStatic<Type>Field() 例如 :int 型別引數 GetStaticIntField()
程式碼目錄:
NdkUtils 類中的 java native 方法
public class NdkUtils {
// 非靜態變數
public String name = "小明";
static {
System.loadLibrary("native-lib");
}
public native String getAccessFiled();
}
cpp目錄下的 native-lib.cpp
#include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_example_cf8_1012_ndk_NdkUtils_getAccessFiled(JNIEnv *env, jobject jobj) { // 獲取jclass 物件,後面要用 jclass clazz = env->GetObjectClass(jobj); // 獲取成員變數的jfieldID jfieldID fieldId = env->GetFieldID(clazz, "name", "Ljava/lang/String;"); // 根據 jfieldID 獲取 該變數的值 jstring jstring1 = (jstring) env->GetObjectField(jobj, fieldId); return jstring1; }
MainActivity.class 中呼叫:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView tv1 = (TextView) findViewById(R.id.sample_text1); tv1.setText(new NdkUtils().getAccessFiled()); } }
執行結果:
詳解:
jfieldID GetFieldID(jclass clazz, const char* name, const char* sig)
獲取非靜態成員變數/方法的方法。
jclass clazz:所屬的類的物件
const char* name :要獲取變數的名稱
const char* sig 所屬型別的簽名
靜態成員變數/方法 對應的方法 : GetStaticFieldID(jclass clazz, const char* name, const char* sig)
下面附上簽名對照表
所屬型別 | 對相簽名(sig) | 示例 |
boolean | Z | |
char | C | |
short | S | |
byte | B | |
int | I | |
long | J | |
float | F | |
double | D | |
void | V | |
object | L開發 ,用 / 分隔包的完整類名。 |
例如 String,則 sig : Ljava/lang/String; object : Ljava/lang/Object |
Array | 已 [ 開頭,在加上陣列的型別名。
|
例如 int[] —> [I int[][] —> [[I |
二、訪問 java 成員靜態成員變數,並修改值:
注: 方法的簽名 是有規律的,需要結合成員變數的簽名
格式: (引數型別)返回值型別
例如: public int add(int a,int b){}
簽名為 : (II)I
這次使用 靜態的native 方法:
public class NdkUtils {
// 靜態屬性 方法
public static String name1="小紅";
public native static String getStaticAccessFiled();
static {
System.loadLibrary("native-lib");
}
}
native-lib.cpp
#include <jni.h>
extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_cf8_1012_ndk_NdkUtils_getStaticAccessFiled(JNIEnv *env, jclass jcla) {
jfieldID jfieldID1 = env->GetStaticFieldID(jcla, "name1", "Ljava/lang/String;");
jstring jstring1 = (jstring) env->GetStaticObjectField(jcla, jfieldID1);
return jstring1;
}
MainActivity.class 中呼叫:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv1 = (TextView) findViewById(R.id.sample_text1);
tv1.setText(NdkUtils.getStaticAccessFiled());
}
}
執行結果:
三、訪問java 中的方法
JNI 呼叫java方法的 方法名格式 : Call<Type>Method() 例如 :CallIntMethod()
JINI呼叫靜態java方法的 方法名格式:CallStatic<Type>Method() 例如 :CallStaticIntMethod()
NdkUtild.class
import java.util.Random;
public class NdkUtils {
// 隨機數方法
public int getRandom(int i) {
return new Random().nextInt(i);
}
public native int accessMethod();
static {
System.loadLibrary("native-lib");
}
}
native.cpp
extern "C"
JNIEXPORT jint JNICALL Java_com_example_cf8_1012_ndk_NdkUtils_accessMethod
(JNIEnv *env, jobject jobj) {
// 獲取 jclass 物件
jclass clazz = env->GetObjectClass(jobj);
// 根據 jclass 方法名 方法簽名 獲取方法的id
jmethodID jmethodID1 = env->GetMethodID(clazz, "getRandom", "(I)I");
// 呼叫 java 中的方法:獲取200 以內的隨機數
jint jint1 = env->CallIntMethod(jobj, jmethodID1, 200);
return jint1;
}
四、訪問Java構造方法
NdkUtils.class
public class NdkUtils {
/**
* 訪問 Date 類的 getTime() 方法
* Date date=new Date();
* long l=date.getTime();
*/
public native long accessCoustomer();
static {
System.loadLibrary("native-lib");
}
}
訪問java 中的 Date 類
native.cpp
/**
* 訪問 java 中 java.util.Date 的構造方法
* */
extern "C"
JNIEXPORT jlong JNICALL
Java_com_example_cf8_1012_ndk_NdkUtils_accessCoustomer(JNIEnv *env, jobject instance) {
// 訪問 java 中 java.util.Date 的構造方法
jclass clazz = env->FindClass("java/util/Date");
//方法簽名的 形式 (引數型別)返回值型別
jmethodID customerId = env->GetMethodID(clazz, "<init>", "()V");
// 例項化一個Date
jobject obj = env->NewObject(clazz, customerId);
// 呼叫Date 的方法
jmethodID methodId = env->GetMethodID(clazz, "getTime", "()J");
// 呼叫方法,獲取返回值 long getTime();
jlong jlong1 = env->CallLongMethod(obj, methodId);
return jlong1;
}