1. 程式人生 > >(四)NDK開發之 java 與C/C++ 程式碼互相呼叫

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