国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用

這篇具有很好參考價(jià)值的文章主要介紹了Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一.概述

上一篇博文《Android:JNI實(shí)戰(zhàn),加載三方庫、編譯C/C++》講解了如何搭建一個(gè)可以加載和鏈接第三方庫、編譯C/C++文件的Jni Demo?App。

這篇博文在這個(gè)Jni Demo App的基礎(chǔ)上,從實(shí)戰(zhàn)出發(fā)詳細(xì)講解?Jni?開發(fā)語法。

接下來,先用一小節(jié)將Jni開發(fā)比較重要的理論知識(shí)點(diǎn)過一下,然后進(jìn)行代碼實(shí)戰(zhàn)演練。

二.理論

2.1?JavaVM 和 JNIEnv

JavaVM JNIEnv 是定義在 jni.h 頭文件中最關(guān)鍵的兩個(gè)結(jié)構(gòu)體

  • JavaVM: 代表 Java 虛擬機(jī),每個(gè) Java進(jìn)程有且僅有一個(gè)全局的 JavaVM 對(duì)象,JavaVM 可以跨線程共享;
  • JNIEnv: 代表 Java運(yùn)行環(huán)境,每個(gè) Java線程都有各自獨(dú)立的 JNIEnv 對(duì)象,JNIEnv 不可以跨線程共享。

JavaVM JNIEnv 的類型定義在 CC++ 中略有不同,但本質(zhì)上是相同的,內(nèi)部由一系列指向虛擬機(jī)內(nèi)部函數(shù)指針組成。

struct _JNIEnv;
struct _JavaVM;
typedef const struct JNINativeInterface* C_JNIEnv;

#if defined(__cplusplus)
 typedef _JNIEnv JNIEnv;
 typedef _JavaVM JavaVM;
#else
 typedef const struct JNINativeInterface* JNIEnv;
 typedef const struct JNIInvokeInterface* JavaVM;
#endif

結(jié)構(gòu)體詳細(xì)定義可翻閱 Jni.h 頭文件,在此不作代碼列舉

2.2.Jni 基礎(chǔ)數(shù)據(jù)類型:

Jni 的數(shù)據(jù)類型都在?jni.h 頭文件中定義,包括基礎(chǔ)數(shù)據(jù)類型int 等)和引用數(shù)據(jù)類型Object、Class數(shù)組等)

(1).C/C++基礎(chǔ)數(shù)據(jù)類型:
/* Primitive types that match up with Java equivalents. */
typedef uint8_t  jboolean; /* unsigned 8 bits */
typedef int8_t   jbyte;    /* signed 8 bits */
typedef uint16_t jchar;    /* unsigned 16 bits */
typedef int16_t  jshort;   /* signed 16 bits */
typedef int32_t  jint;     /* signed 32 bits */
typedef int64_t  jlong;    /* signed 64 bits */
typedef float    jfloat;   /* 32-bit IEEE 754 */
typedef double   jdouble;  /* 64-bit IEEE 754 */

/* "cardinal indices and sizes" */
typedef jint     jsize;
(2).C++引用數(shù)據(jù)類型:
#ifdef __cplusplus
/*
 * Reference types, in C++
 */
class _jobject {};
class _jclass : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jobjectArray : public _jarray {};
class _jbooleanArray : public _jarray {};
class _jbyteArray : public _jarray {};
class _jcharArray : public _jarray {};
class _jshortArray : public _jarray {};
class _jintArray : public _jarray {};
class _jlongArray : public _jarray {};
class _jfloatArray : public _jarray {};
class _jdoubleArray : public _jarray {};
class _jthrowable : public _jobject {};

typedef _jobject*       jobject;
typedef _jclass*        jclass;
typedef _jstring*       jstring;
typedef _jarray*        jarray;
typedef _jobjectArray*  jobjectArray;
typedef _jbooleanArray* jbooleanArray;
typedef _jbyteArray*    jbyteArray;
typedef _jcharArray*    jcharArray;
typedef _jshortArray*   jshortArray;
typedef _jintArray*     jintArray;
typedef _jlongArray*    jlongArray;
typedef _jfloatArray*   jfloatArray;
typedef _jdoubleArray*  jdoubleArray;
typedef _jthrowable*    jthrowable;
typedef _jobject*       jweak;
(3).C引用數(shù)據(jù)類型:
/*
 * Reference types, in C.
 */
typedef void*           jobject;
typedef jobject         jclass;
typedef jobject         jstring;
typedef jobject         jarray;
typedef jarray          jobjectArray;
typedef jarray          jbooleanArray;
typedef jarray          jbyteArray;
typedef jarray          jcharArray;
typedef jarray          jshortArray;
typedef jarray          jintArray;
typedef jarray          jlongArray;
typedef jarray          jfloatArray;
typedef jarray          jdoubleArray;
typedef jobject         jthrowable;
typedef jobject         jweak;
(4).與Java數(shù)據(jù)類型映射表:
Java 類型 JNI 類型 描述 長度(字節(jié))
boolean jboolean unsigned char 1
byte jbyte signed char 1
char jchar unsigned short 2
short jshort signed short 2
int jint、jsize signed int 4
long jlong signed long 8
float jfloat signed float 4
double jdouble signed double 8
Class jclass Class 類對(duì)象 1
String jstrting 字符串對(duì)象 /
Object jobject 對(duì)象 /
Throwable jthrowable 異常對(duì)象 /
boolean[] jbooleanArray 布爾數(shù)組 /
byte[] jbyteArray byte 數(shù)組 /
char[] jcharArray char 數(shù)組 /
short[] jshortArray short 數(shù)組 /
int[] jinitArray int 數(shù)組 /
long[] jlongArray long 數(shù)組 /
float[] jfloatArray float 數(shù)組 /
double[] jdoubleArray double 數(shù)組 /

2.3 JNI 訪問 Java 字段 (成員變量)

Jni?訪問 Java 字段的流程分為 2 步:

  • 1.通過 jclass 獲取字段 ID。例:Fid = env->GetFieldId(clz, "name", "Ljava/lang/String;");
  • 2.通過字段 ID 訪問字段。例:Jstr = env->GetObjectField(thiz, Fid);

Java 字段分為靜態(tài)字段非靜態(tài)字段,相關(guān)方法如下:

  • GetFieldId:獲取非靜態(tài)字段 ID
  • GetStaticFieldId:獲取靜態(tài)字段 ID
  • GetField:獲取類型為 Type 非靜態(tài)字段(例如 GetIntField
  • SetField:設(shè)置類型為 Type 非靜態(tài)字段(例如 SetIntField
  • GetStaticField:獲取類型為 Type 靜態(tài)字段(例如 GetStaticIntField
  • SetStaticField:設(shè)置類型為 Type 靜態(tài)字段(例如 SetStaticIntField

2.4 Jni?調(diào)用 Java 方法

Jni?訪問 Java 方法與訪問 Java 字段類似,訪問流程分為 2 步:

  • 1、通過 jclass 獲取「方法 ID」。例:Mid = env->GetMethodID(jclass, "helloJava", "()V");
  • 2、通過方法 ID 調(diào)用方法。例:env->CallVoidMethod(thiz, Mid);

Java 方法分為靜態(tài)方法非靜態(tài)方法,相關(guān)方法如下:

  • GetMethodId:獲取非靜態(tài)方法 ID
  • GetStaticMethodId:獲取靜態(tài)方法 ID
  • CallMethod:調(diào)用返回類型為 Type 非靜態(tài)方法(例如 GetVoidMethod
  • CallStaticMethod:調(diào)用返回類型為 Type 靜態(tài)方法(例如 CallStaticVoidMethod
  • CallNonvirtualMethod:調(diào)用返回類型為 Type 的父類方法(例如 CallNonvirtualVoidMethod

2.5?描述符:

Jni在調(diào)用Java 字段(成員變量)函數(shù)時(shí),需要用描述符對(duì)變量、函數(shù)參數(shù) 、函數(shù)返回值類型進(jìn)行簽名描述

字段描述符:描述字段(成員變量)的類型。

JVM 對(duì)每種基礎(chǔ)數(shù)據(jù)類型定義了固定的描述符,而引用類型則是以 L 開頭的形式:

Java 類型 描述符
boolean Z
byte B
char C
short S
int I
long J
floag F
double D
void V
引用類型 以 L 開頭 ; 結(jié)尾,中間是 / 分隔的包名和類名。例如 String 的字段描述符為 Ljava/lang/String;

方法描述符:?描述方法的返回值類型參數(shù)表類型

參數(shù)類型用一對(duì)圓括號(hào)括起來,按照參數(shù)聲明順序列舉參數(shù)類型,返回值出現(xiàn)在括號(hào)后面。

例如方法 void fun()?的名稱為 fun,方法描述符為 ()V

三.實(shí)戰(zhàn)

上一篇博文中Jni Demo App的代碼結(jié)構(gòu)圖

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


3.1 Java調(diào)用Jni?

(1).Java從Jni?獲取一個(gè)String

這也是AndroidStudio默認(rèn)創(chuàng)建的Native C++ Demo里的

jnidemo.cpp

Jni函數(shù)名前綴要與Java聲明Native函數(shù)所在文件的包名+文件名對(duì)應(yīng)

extern "C" {

JNIEXPORT jstring JNICALL
Java_com_android_demo_jni_JNIDEMO_JavaGetStringFromJNI(JNIEnv *env, jobject instance) {
	string hello = "Hello from C++";
	return env->NewStringUTF(hello.c_str());
}

}

JNIDEMO.java

public class JNIDEMO {

    //Java從Jni獲取String
    public native String JavaGetStringFromJNI();

}

JniActivity.java

通過JNIDEMO實(shí)例對(duì)象調(diào)用聲明的Native方法,實(shí)現(xiàn)對(duì)Jni函數(shù)的調(diào)用

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

        String jniStr = mJniDemo.JavaGetStringFromJNI();
        Log.v(TAG, "jniStr:" + jniStr);

   }
}

日志打印:

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


(2).Java傳一個(gè)Int[]到Jni,Jni直接處理Int[]數(shù)據(jù)

jnidemo.cpp

extern "C" {

/***** java傳遞一個(gè)Int[]到Jni, Jni賦值后再返回給Java *****/
JNIEXPORT void JNICALL
Java_com_android_demo_jni_JNIDEMO_JavaJniTransIntArray(JNIEnv *env, jobject instance,
                                                       jintArray javaArr) {
    //獲取Java數(shù)組長度
    int lenght = env->GetArrayLength(javaArr);

    //GetIntArrayElements() 函數(shù)作用就是將 jintArray 轉(zhuǎn)為 int* 指針;  將本地指針指向含有Java端數(shù)組的內(nèi)存地址
    //依賴Jvm的具體實(shí)現(xiàn),可能是鎖住Java端的那段數(shù)組不被回收(增加引用計(jì)數(shù)),也可能所Jvm在堆上對(duì)該數(shù)組的一份拷貝,速度和效率比GetIntArrayRegion方法要高很多
    int *arrp = env->GetIntArrayElements(javaArr, 0);

    //對(duì)數(shù)組元素進(jìn)行處理
    for (int i = 0; i < lenght; i++) {
        *(arrp + i) += i;
    }

    //將C數(shù)組種的元素拷貝到Java數(shù)組中
    env->SetIntArrayRegion(javaArr, 0, lenght, arrp);

    //如果需要,可以返回?cái)?shù)組
    //return javaArr;
}

}

JNIDEMO.java

public class JNIDEMO {

    //Java傳一個(gè)Int[]到Jni進(jìn)行數(shù)據(jù)處理
    public native void JavaJniTransIntArray(int[] arrInt);

}

JniActivity.java

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

        //Java傳一個(gè)int[]到Jni,Jni對(duì)int[]元素進(jìn)行修改
        int[] arrInt = new int[10];
        Log.v(TAG, "BeforCallJni  arrInt[]:" + Arrays.toString(arrInt));
        mJniDemo.JavaJniTransIntArray(arrInt);
        Log.v(TAG, "AfterCallJni  arrInt[]:" + Arrays.toString(arrInt));

   }
}

日志打印:

可以看到在調(diào)用Jni函數(shù)之前,數(shù)組元素都是初始值0,經(jīng)過Jni處理之后數(shù)值就改變了

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


(3).Java傳一個(gè)byte[]到Jni,Jni直接處理byte[]數(shù)據(jù)

jnidemo.cpp

extern "C" {

JNIEXPORT void JNICALL
Java_com_android_demo_jni_JNIDEMO_JavaJniTransByteArray1(JNIEnv *env, jobject instance,
                                                         jbyteArray javaArr) {
    //獲取Java數(shù)組長度
    int lenght = env->GetArrayLength(javaArr);

    //將 jbyteArray 轉(zhuǎn)為 int* 指針,使用本地指針指向含有Java端數(shù)組的內(nèi)存地址
    //依賴Jvm的具體實(shí)現(xiàn),可能是鎖住Java端的那段數(shù)組不被回收(增加引用計(jì)數(shù)),也可能所Jvm在堆上對(duì)該數(shù)組的一份拷貝,速度和效率比GetIntArrayRegion方法要高很多
    jbyte *arrp = env->GetByteArrayElements(javaArr, 0);
    //另外兩種方式
    //signed char jbp1[lenght];
    //signed char *jbp2 = env->GetByteArrayElements(javaArr, 0);

    //對(duì)數(shù)組元素進(jìn)行處理
    for (int i = 0; i < lenght; i++) {
        *(arrp + i) += i;
    }

    //將C數(shù)組中的元素拷貝到Java數(shù)組中
    env->SetByteArrayRegion(javaArr, 0, lenght, arrp);

    //如果需要,可以返回?cái)?shù)組
    //return javaArr;
}

}

JNIDEMO.java

public class JNIDEMO {

    //Java傳一個(gè)byte[]到Jni,Jni對(duì)byte[]數(shù)據(jù)處理
    public native void JavaJniTransByteArray1(byte[] arrByte);

}

JniActivity.java

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

        //Java傳一個(gè)byte[]到Jni,Jni對(duì)int[]元素進(jìn)行修改
        byte[] arrbyte1 = new byte[10];
        Log.v(TAG, "BeforCallJni  arrbyte1[]:" + Arrays.toString(arrbyte1));
        mJniDemo.JavaJniTransByteArray1(arrbyte1);
        Log.v(TAG, "AfterCallJni  arrbyte1[]:" + Arrays.toString(arrbyte1));

   }
}

日志打印:

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


(4).Java傳一個(gè)byte[]到Jni,Jni拷貝數(shù)據(jù)到native byte[],處理數(shù)據(jù)后再返回native byte[]給Java

jnidemo.cpp

extern "C" {

JNIEXPORT jbyteArray JNICALL
Java_com_android_demo_jni_JNIDEMO_JavaJniTransByteArray2(JNIEnv *env, jobject instance,
                                                         jbyteArray javaArr) {
    //獲取Java數(shù)組長度
    int lenght = env->GetArrayLength(javaArr);

    //新建一個(gè)jni byte指針,指向一塊 byte數(shù)據(jù)內(nèi)存
    jbyte *jbp = (jbyte *) malloc(lenght * sizeof(jbyte));

    //直接將Java端的數(shù)組拷貝到本地jni內(nèi)存中
    env->GetByteArrayRegion(javaArr, 0, lenght, jbp);

    //對(duì)數(shù)組元素進(jìn)行處理
    for (int i = 0; i < lenght; i++) {
        *(jbp + i) += i;
    }

    //新建一個(gè)jni byte數(shù)組
    jbyteArray arrjb = env->NewByteArray(lenght);

    //將jni byte指針?biāo)竷?nèi)存中的元素拷貝到生成的C數(shù)組中,然后返回
    env->SetByteArrayRegion(arrjb, 0, lenght, jbp);

    //如果需要,可以返回?cái)?shù)組
    return arrjb;
}

}

JNIDEMO.java

public class JNIDEMO {

    //Java傳一個(gè)byte[]到Jni,Jni拷貝數(shù)據(jù)到native byte[],處理數(shù)據(jù)后再返回native byte[]給Java
    public native byte[] JavaJniTransByteArray2(byte[] arrByte);

}

JniActivity.java

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

        byte[] arrbyte2 = new byte[10];
        byte[] arrbyte3 = new byte[10];

        Log.v(TAG, "BeforCallJni  arrbyte2[]:" + Arrays.toString(arrbyte2));
        Log.v(TAG, "BeforCallJni  arrbyte3[]:" + Arrays.toString(arrbyte3));

        arrbyte3 = mJniDemo.JavaJniTransByteArray2(arrbyte2);

        Log.v(TAG, "AfterCallJni  arrbyte2[]:" + Arrays.toString(arrbyte2));
        Log.v(TAG, "BeforCallJni  arrbyte3[]:" + Arrays.toString(arrbyte3));

   }
}

日志打?。?/strong>

新建了兩個(gè)byte[]arrbyte2[]?arrbyte3[]?。

arrbyte2[]?作為參數(shù)傳遞到Jni,arrbyte3[]?用于被Jni返回的Native byte[]賦值

可以看到,arrbyte2[]?,arrbyte3[]?在調(diào)用JavaJniTransByteArray2()之前,都是初始值0,在調(diào)用之后,由于arrbyte2[]Jni中其元素并沒有被改變,所以打印出來仍然都是0,而arrbyte3[]元素值則是Jni返回的Native byte[]的元素值。

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


(5).Java調(diào)用Jni啟動(dòng)一個(gè)線程

jnidemo.h

extern "C" {

bool running = false;

void *JniThreadStartByJava(void *arg);

}

jnidemo.cpp

extern "C" {

/***** java 啟動(dòng)一個(gè) jni 線程 *****/
JNIEXPORT void JNICALL
Java_com_android_demo_jni_JNIDEMO_JavaStartJNIThread(JNIEnv *env, jobject instance) {
    pthread_t myThread;
    int res = pthread_create(&myThread, NULL, JniThreadStartByJava, NULL);
    if (res != 0) {
        LOGW("JniThreadStartByJava create failed!");
        return;
    }
}

void *JniThreadStartByJava(void *arg) {
    LOGW("JniThreadStartByJava create success!");

    while (running) {
        //do the thread thing...
    }
    return NULL;
}

}

JNIDEMO.java

public class JNIDEMO {

    //Java啟動(dòng)一個(gè)Jni線程
    public native void JavaStartJNIThread();
}

JniActivity.java

通過JNIDEMO實(shí)例對(duì)象調(diào)用聲明的Native方法,實(shí)現(xiàn)對(duì)Jni函數(shù)的調(diào)用

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

        //java啟動(dòng)一個(gè)jni線程
        mJniDemo.JavaStartJNIThread();

   }
}

日志打印:

可以看到,在?Java?成功的創(chuàng)建和啟動(dòng)?Jni?中的一個(gè)線程

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)

3.2 Jni調(diào)用Java


(1).Jni調(diào)用Java非靜態(tài)成員變量

jnidemo.cpp

extern "C" {

/**** jni訪問java非靜態(tài)成員變量 ****/
/* 1.使用 GetObjectClass、 FindClass獲取調(diào)用對(duì)象的類
*  2.使用 GetFieldID 獲取字段的ID。這里需要傳入字段類型的簽名描述。
*  3.使用 GetIntField、 GetObjectField等方法,獲取字段的值。
*  4.使用 SetIntField、 SetObjectField等方法,設(shè)置字段的值。
*  注意:即使字段是 private也照樣可以正常訪問。*/
JNIEXPORT void JNICALL
Java_com_android_demo_jni_JNIDEMO_JniCallJavaNoStaticField(JNIEnv *env, jobject instance) {
    //獲取jclass
    jclass j_class = env->GetObjectClass(instance);
    //獲取jfieldID
    jfieldID j_fid = env->GetFieldID(j_class, "mNoStaticField", "I");
    //獲取java成員變量int值
    jint j_int = env->GetIntField(instance, j_fid);
    //noStaticField==0
    LOGI("noStaticField==%d", j_int);
    //Set<Type>Field 修改noStaticKeyValue的值改為111
    env->SetIntField(instance, j_fid, 111);
}

}

JNIDEMO.java

public class JNIDEMO {

    //非靜態(tài)成員變量
    public int mNoStaticField;

    //Jni調(diào)用Java非靜態(tài)成員變量
    public native void JniCallJavaNoStaticField();

}

JniActivity.java

通過JNIDEMO實(shí)例對(duì)象調(diào)用聲明的Native方法,實(shí)現(xiàn)對(duì)Jni函數(shù)的調(diào)用

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

	  //jni調(diào)用Java非靜態(tài)成員變量
	  Log.v(TAG, "BeforCallJni   mJni.mNoStaticField:" + mJniDemo.mNoStaticField);
	  mJniDemo.JniCallJavaNoStaticField();
	  Log.v(TAG, "AfterCallJni   mJni.mNoStaticField:" + mJniDemo.mNoStaticField);

   }
}

日志打?。?/strong>

可以看到,在Jni中對(duì)Java非靜態(tài)成員變量的值進(jìn)行了改變

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


(2).Jni調(diào)用Java靜態(tài)成員變量

jnidemo.cpp

Jni函數(shù)名前綴要與Java聲明Native函數(shù)所在文件的包名+文件名對(duì)應(yīng)

extern "C" {

/**** jni訪問java靜態(tài)成員變量 ****/
/* 1.使用 GetObjectClass、 FindClass獲取調(diào)用對(duì)象的類
*  2.使用 GetStaticFieldID 獲取字段的ID。這里需要傳入字段類型的簽名描述。
*  3.使用 GetStaticIntField、 GetStaticObjectField 等方法,獲取字段的值。
*  4.使用 SetStaticIntField、 SetStaticObjectField 等方法,設(shè)置字段的值。
*  注意:即使字段是 private也照樣可以正常訪問。*/
JNIEXPORT void JNICALL
Java_com_android_demo_jni_JNIDEMO_JniCallJavaStaticField(JNIEnv *env, jobject instance) {
    //獲取jclass
    jclass j_class = env->GetObjectClass(instance);
    //獲取jfieldID
    jfieldID j_fid = env->GetStaticFieldID(j_class, "mStaticField", "I");
    //獲取java成員變量int值
    jint j_int = env->GetStaticIntField(j_class, j_fid);
    //noStaticField==0
    LOGI("StaticField==%d", j_int);

    //Set<Type>Field 修改noStaticKeyValue的值改為666
    env->SetStaticIntField(j_class, j_fid, 222);
}

}

JNIDEMO.java

public class JNIDEMO {

    //靜態(tài)成員變量
    public static int mStaticField;

    //Jni調(diào)用Java靜態(tài)成員變量
    public native void JniCallJavaStaticField();

}

JniActivity.java

通過JNIDEMO實(shí)例對(duì)象調(diào)用聲明的Native方法,實(shí)現(xiàn)對(duì)Jni函數(shù)的調(diào)用

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

      //Jni調(diào)用Java靜態(tài)成員變量
      Log.v(TAG, "BeforCallJni   mJni.mStaticField:" + mJniDemo.mStaticField);
      mJniDemo.JniCallJavaStaticField();
      Log.v(TAG, "AfterCallJni   mJni.mStaticField:" + mJniDemo.mStaticField);

   }
}

日志打?。?/strong>

可以看到,在Jni中對(duì)Java靜態(tài)成員變量的值進(jìn)行了改變

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


(3).Jni調(diào)用Java非靜態(tài)成員方法

jnidemo.cpp

Jni函數(shù)名前綴要與Java聲明Native函數(shù)所在文件的包名+文件名對(duì)應(yīng)

extern "C" {

/**** jni調(diào)用java非靜態(tài)成員方法 ****/
/* 1.使用 GetObjectClass、 FindClass獲取調(diào)用對(duì)象的類
*  2.使用 GetMethodID獲取方法的ID。這里需要傳入方法的簽名描述。
*  3.使用 CallVoidMethod執(zhí)行無返回值的方法
*  4.使用 CallIntMethod、 CallBooleanMethod、CallStringMethod等執(zhí)行有返回值的方法。
*  注意:即使字段是 private也照樣可以正常訪問。*/
JNIEXPORT void JNICALL
Java_com_android_demo_jni_JNIDEMO_JniCallJavaNoStaticMethod(JNIEnv *env, jobject instance) {
    //回調(diào)JNI.java中的noParamMethod
    jclass clazz = env->FindClass("com/android/demo/jni/JNIDEMO");
    if (clazz == NULL) {
        printf("find class Error");
        return;
    }
    jmethodID method = env->GetMethodID(clazz, "noStaticMethod", "(I)I");
    if (method == NULL) {
        printf("find method Error");
        return;
    }
    env->CallIntMethod(instance, method, 333);
}

}

JNIDEMO.java

public class JNIDEMO {

    //非靜態(tài)成員方法
    private int noStaticMethod(int number) {
        Log.v(TAG,"noStaticMethod() number: "+number);
        return number;
    }

    //Jni調(diào)用Java非靜態(tài)成員方法
    public native void JniCallJavaNoStaticMethod();

}

JniActivity.java

通過JNIDEMO實(shí)例對(duì)象調(diào)用聲明的Native方法,實(shí)現(xiàn)對(duì)Jni函數(shù)的調(diào)用

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

      //Jni調(diào)用Java非靜態(tài)成員方法
      mJniDemo.JniCallJavaNoStaticMethod();

   }

}

日志打?。?/strong>

可以看到,Jni調(diào)用一個(gè)帶整型參數(shù)的Java非靜態(tài)成員方法,并且在Jni給這個(gè)方法傳參333

運(yùn)行后,這個(gè)Java非靜態(tài)成員方法中的Log打印如下:

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


(4).Jni調(diào)用Java靜態(tài)成員方法

jnidemo.cpp

Jni函數(shù)名前綴要與Java聲明Native函數(shù)所在文件的包名+文件名對(duì)應(yīng)

extern "C" {

/**** jni調(diào)用java靜態(tài)成員方法 ****/
/*1.使用 GetObjectClass、 FindClass獲取調(diào)用對(duì)象的類
* 2.使用 GetStaticMethodID 獲取方法的ID。這里需要傳入方法的簽名描述。
* 3.使用 CallStaticVoidMethod 執(zhí)行無返回值的方法。
* 4.使用 CallStaticIntMethod、 CallStaticBooleanMethod 等執(zhí)行有返回值的方法。
* 注意:即使字段是 private也照樣可以正常訪問。*/
JNIEXPORT void JNICALL
Java_com_android_demo_jni_JNIDEMO_JniCallJavaStaticMethod(JNIEnv *env, jobject instance) {
    //回調(diào)JNI.java中的noParamMethod
    jclass clazz = env->FindClass("com/android/demo/jni/JNIDEMO");
    if (clazz == NULL) {
        printf("find class Error");
        return;
    }
    jmethodID method = env->GetStaticMethodID(clazz, "staticMethod", "(I)I");
    if (method == NULL) {
        printf("find method Error");
        return;
    }
    env->CallStaticIntMethod(clazz, method, 444);
}

}

JNIDEMO.java

public class JNIDEMO {

    //靜態(tài)成員方法
    private static int staticMethod(int number) {
        Log.v(TAG,"staticMethod() number: "+number);
        return number;
    }

    //Jni調(diào)用Java靜態(tài)成員方法
    public native void JniCallJavaStaticMethod();

}

JniActivity.java

通過JNIDEMO實(shí)例對(duì)象調(diào)用聲明的Native方法,實(shí)現(xiàn)對(duì)Jni函數(shù)的調(diào)用

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

       //jni調(diào)用Java靜態(tài)成員方法
       mJniDemo.JniCallJavaStaticMethod();

   }

}

日志打?。?/strong>

可以看到,Jni調(diào)用一個(gè)帶整型參數(shù)的Java非靜態(tài)成員方法,并且在Jni給這個(gè)方法傳參333

運(yùn)行后,這個(gè)Java非靜態(tài)成員方法中的Log打印如下:

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


(5).Jni調(diào)用Java類的構(gòu)造函數(shù)

新建一個(gè)JNIConstruct.java類,其中包含一個(gè)Int和一個(gè)String成員變量。

Jni調(diào)用JNIConstruct.java類的構(gòu)造函數(shù),實(shí)現(xiàn)通過Jni調(diào)用構(gòu)造函數(shù)傳參,給這兩個(gè)成員變量賦值

JNIConstruct.java

package com.android.demo.jni;

import android.util.Log;

public class JNIConstruct {
    private final String TAG = "JNIConstruct";

    private int paramInt = 0;
    private String paramStr = null;

    public JNIConstruct(int intp, String strp) {
        paramInt = intp;
        paramStr = strp;
    }

    public void printf() {
        Log.v(TAG, "printf()  paramInt:" + paramInt + " paramStr:" + paramStr);
    }

}

jnidemo.cpp

Jni函數(shù)名前綴要與Java聲明Native函數(shù)所在文件的包名+文件名對(duì)應(yīng)

extern "C" {

/***** jni調(diào)用java構(gòu)造方法 *****/
/* 1.使用 FindClass 獲取需要構(gòu)造的類
 * 2.使用 GetMethodID 獲取構(gòu)造方法的ID。方法名為 <init>, 這里需要傳入方法的簽名描述。
 * 3.使用 NewObject 執(zhí)行創(chuàng)建對(duì)象。*/
JNIEXPORT jobject JNICALL
Java_com_android_demo_jni_JNIDEMO_JniCallJavaConstructMethod(JNIEnv *env, jobject instance) {
    // 1、獲取 JNIConstruct 類的 class 引用
    jclass cls_jniCons = env->FindClass("com/android/demo/jni/JNIConstruct");
    if (cls_jniCons == NULL) {
        return NULL;
    }

    // 2、獲取 JNIConstruct 的構(gòu)造方法ID (構(gòu)造方法的名稱統(tǒng)一為:<init>)
    jmethodID med_jniCons = env->GetMethodID(cls_jniCons, "<init>", "(ILjava/lang/String;)V");
    if (med_jniCons == NULL) {
        return NULL; // 沒有找到參數(shù)為int和String的構(gòu)造方法
    }

    // 3、創(chuàng)建JNIConstruct對(duì)象的實(shí)例(調(diào)用對(duì)象的構(gòu)造方法并初始化對(duì)象), env->NewStringUTF("") 創(chuàng)建一個(gè) String 對(duì)象,作為構(gòu)造方法的第二個(gè) String 類型參數(shù)
    jobject obj_jniCons = env->NewObject(cls_jniCons, med_jniCons, 555,
                                         env->NewStringUTF("Jni Construct!"));
    if (obj_jniCons == NULL) {
        return NULL;
    }

    return obj_jniCons;
}

}

JNIDEMO.java

public class JNIDEMO {

    //Jni調(diào)用Java類的構(gòu)造函數(shù)
    public native JNIConstruct JniCallJavaConstructMethod();

}

JniActivity.java

通過JNIDEMO實(shí)例對(duì)象調(diào)用聲明的Native方法,實(shí)現(xiàn)對(duì)Jni函數(shù)的調(diào)用

public class JniActivity{

   private JNIDEMO mJniDemo = new JNIDEMO();

   publice void JavaJniFun(){

       //jni調(diào)用Java構(gòu)造函數(shù)
       JNIConstruct jniConstruct = mJniDemo.JniCallJavaConstructMethod();
       jniConstruct.printf();

   }

}

日志打?。?/strong>

可以看到,Jni調(diào)用了JNIConstruct.java的構(gòu)造函數(shù),并傳遞兩個(gè)參數(shù):

  • int paramInt = 555;
  • String paramStr = Jni Construct!;

Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用,Android,android,數(shù)據(jù)結(jié)構(gòu)


四.結(jié)束語?

Jni 實(shí)戰(zhàn)開發(fā)到此講解完畢,篇幅有限,無法所有場(chǎng)景都實(shí)戰(zhàn)涉及,但是萬變不離其宗。

掌握了Jni理論基礎(chǔ),實(shí)踐了多種類型Jni與Java互相調(diào)用后,其他都只是在此基礎(chǔ)上的擴(kuò)展了。文章來源地址http://www.zghlxwxcb.cn/news/detail-818648.html

到了這里,關(guān)于Android:JNI實(shí)戰(zhàn),理論詳解、Java與Jni數(shù)據(jù)調(diào)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Android之 JNI詳解

    一、JNI簡(jiǎn)介 JNI 是Java Native Interface的縮寫,表示Java本地調(diào)用,通過JNI技術(shù)可以實(shí)現(xiàn)Java調(diào)用C程序和C程序調(diào)用Java代碼。 二、JNI函數(shù)注冊(cè) 2.1 靜態(tài)注冊(cè): 靜態(tài)注冊(cè)的方式我們平時(shí)用的比較多。我們通過javac和javah編譯出頭文件,然后再實(shí)現(xiàn)對(duì)應(yīng)的cpp文件的方式就是屬于靜態(tài)注冊(cè)的

    2024年04月27日
    瀏覽(18)
  • Android Studio 進(jìn)行NDK開發(fā),實(shí)現(xiàn)JNI,以及編寫C++與Java交互(Java調(diào)用本地函數(shù))并編譯出本地so動(dòng)態(tài)庫

    Android Studio 進(jìn)行NDK開發(fā),實(shí)現(xiàn)JNI,以及編寫C++與Java交互(Java調(diào)用本地函數(shù))并編譯出本地so動(dòng)態(tài)庫

    1.首先認(rèn)識(shí)一下NDK。 (1)什么是NDK? NDK全稱是Native Development Kit,NDK提供了一系列的工具,幫助開發(fā)者快速開發(fā)C/C++的動(dòng)態(tài)庫,并能自動(dòng)將so和java應(yīng)用一起打包成apk。NDK集成了交叉編譯器(交叉編譯器需要UNIX或LINUX系統(tǒng)環(huán)境),并提供了相應(yīng)的mk文件隔離CPU、平臺(tái)、ABI等差異,

    2024年02月11日
    瀏覽(35)
  • Android音視頻開發(fā)實(shí)戰(zhàn)02-Jni

    Android音視頻開發(fā)實(shí)戰(zhàn)02-Jni

    JNI是Java Native Interface的縮寫,是Java提供的一種機(jī)制,用于在Java代碼中調(diào)用本地(C/C++)代碼。它允許Java代碼與本地代碼進(jìn)行交互,通過JNI,Java應(yīng)用程序可以調(diào)用一些原生庫或者操作系統(tǒng)API,以獲取更好的性能和更強(qiáng)的功能支持。 使用JNI需要編寫一些Native方法,并將其實(shí)現(xiàn)在

    2024年02月11日
    瀏覽(30)
  • Android Native Code開發(fā)學(xué)習(xí)(二)JNI互相傳參返回調(diào)用

    Android Native Code開發(fā)學(xué)習(xí)(二)JNI互相傳參返回調(diào)用

    本教程為native code學(xué)習(xí)筆記,希望能夠幫到有需要的人 我的電腦系統(tǒng)為ubuntu 22.04,當(dāng)然windows也是可以的,區(qū)別不大 native code就是在android項(xiàng)目中混合C++或者C語言進(jìn)行開發(fā),這樣的好處是很多底層的東西需要使用C++/C的語言進(jìn)行操作,而且在android開發(fā)中,使用C++和C混合開發(fā)能夠

    2024年02月11日
    瀏覽(15)
  • Android Java代碼與JNI交互 JNI訪問Java構(gòu)造方法(九)

    Android Java代碼與JNI交互 JNI訪問Java構(gòu)造方法(九)

    ?? Android Studio 版本 ???? ??? 創(chuàng)建包含JNI相關(guān)函數(shù)類 JNIConstructorClass.java ?? ??? 配置動(dòng)態(tài)庫名稱 ??? ??? 生成可關(guān)聯(lián)的庫鏈接 ??? 為了讓Java能夠調(diào)用?constructor-class-lib 庫中的函數(shù),您需要使用 CMake 構(gòu)建腳本中的?target_link_libraries()?命令來關(guān)聯(lián)constructor-class-lib 庫 ???

    2024年02月15日
    瀏覽(50)
  • Android Java代碼與JNI交互 JNI方法Java類字段 (六)

    Android Java代碼與JNI交互 JNI方法Java類字段 (六)

    ?? Android Studio 版本 ???? ??? Java 基礎(chǔ)類型數(shù)據(jù)對(duì)應(yīng) Native層的字母 ?? ?通過 jni 查找java某個(gè)類中相應(yīng)字段對(duì)應(yīng)的數(shù)據(jù)類型 , 需要使用到 jni 中的 GetFieldID() 函數(shù) ?? Java 引用類型數(shù)據(jù)對(duì)應(yīng) Native層字符串???? ??? 創(chuàng)建 JNIAccessField 文件 ?? ?? 配置動(dòng)態(tài)庫名稱 ??? ?? 生成

    2024年02月16日
    瀏覽(20)
  • Android Java代碼與JNI交互 JNI訪問Java類方法 (七)

    Android Java代碼與JNI交互 JNI訪問Java類方法 (七)

    ?? Android Studio 版本 ???? ??? 創(chuàng)建包含JNI的類 JNIAccessMethod.java ?? ??? Java方法對(duì)應(yīng)Native層方法名稱 ?? ?? 配置動(dòng)態(tài)庫名稱 ??? ?? 生成可關(guān)聯(lián)的庫鏈接 ??? 為了讓Java能夠調(diào)用?access-method-lib 庫中的函數(shù),您需要使用 CMake 構(gòu)建腳本中的?target_link_libraries()?命令來關(guān)聯(lián)?

    2024年02月16日
    瀏覽(23)
  • Android Studio中使用cmake開發(fā)JNI實(shí)戰(zhàn)

    Android Studio中使用cmake開發(fā)JNI實(shí)戰(zhàn)

    JNI學(xué)習(xí)大綱 一、JNI編程入門 二、Android Studio中使用cmake開發(fā)JNI實(shí)戰(zhàn) 第一章節(jié)我們介紹了JNI的開發(fā)步驟,那這一章節(jié)我們就開始在Android Studio中實(shí)戰(zhàn)一下吧,Let\\\'s Start。 AS中菜單欄選擇ToolsSDK Manager 在Android SDK中選擇SDK Tools,安裝CMake和NDK。 在項(xiàng)目工程下的src/main創(chuàng)建cpp目錄,編

    2024年02月14日
    瀏覽(25)
  • Android Java代碼與JNI交互 JNI子線程訪問Java方法 (八)

    Android Java代碼與JNI交互 JNI子線程訪問Java方法 (八)

    ?? Android Studio 版本 ???? ?? 創(chuàng)建包含JNI相關(guān)函數(shù)類 JNIInvokeMethod.java ?? ??? 配置動(dòng)態(tài)庫名稱 ??? ?? 生成可關(guān)聯(lián)的庫鏈接 ??? 為了讓Java能夠調(diào)用?invoke-method-lib 庫中的函數(shù),您需要使用 CMake 構(gòu)建腳本中的?target_link_libraries()?命令來關(guān)聯(lián)?invoke-method-lib 庫 ??? 提供給N

    2024年02月16日
    瀏覽(25)
  • Android:JNI實(shí)戰(zhàn),加載三方庫、編譯C/C++

    Android:JNI實(shí)戰(zhàn),加載三方庫、編譯C/C++

    Android Jni 機(jī)制讓開發(fā)者可以在 Java 端調(diào)用到 C/C++ ,也是 Android 應(yīng)用開發(fā)需要掌握的一項(xiàng)重要的基礎(chǔ)技能。 計(jì)劃分兩篇博文講述 Jni 實(shí)戰(zhàn)開發(fā)。 本篇主要從 項(xiàng)目架構(gòu) 上剖析一個(gè) Android App 如何通過 Jni機(jī)制 加載 三方庫 和 C/C++文件 。? Android Studio 可以直接創(chuàng)建一個(gè)可運(yùn)行的、最

    2024年01月22日
    瀏覽(15)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包