1. 程式人生 > >JNI 呼叫java裡的基本型別和物件

JNI 呼叫java裡的基本型別和物件

主要是介紹jni呼叫基本型別和物件,包含例項物件和靜態物件

先上mylog.h檔案

#include<android/log.h>

#ifndef TEST_JNI_LOG_H
#define TEST_JNI_LOG_H

#define TAG "myjni-TAG" // 這個是自定義的LOG的標識
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定義LOGD型別
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定義LOGI型別
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定義LOGW型別
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定義LOGE型別
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定義LOGF型別

#endif //TEST_JNI_LOG_H

在上java檔案

Person.java
package com.test.myjnitest;

/**
 * Created by Administrator on 2018/9/6 0006.
 */

public class Person {
    private int age;
    private String name;
    private static String school;

    public Person() {
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static void setSchool(String sch){
        school=sch;
    }

    public static String getSchool(){
        return school;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

接著是StateListener.java

package com.test.myjnitest;

/**
 * Created by Administrator on 2018/9/6 0006.
 */

public interface StateListener {
    void onStateChange(int code, String msg);
    void onModifyValue(Person person);
}

重要程式碼出現了

​
package com.test.myjnitest;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.util.Arrays;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "myjniTest";
    private Person xiaoming;
    private static String sex;

    private static Person xiaohua;

    private static final int MSG_ID = 0x100;

    TextView tv;

    private int msg_code;

    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_ID:
                    callListerner(msg_code++);
                    if (msg_code < 10){
                        mHandler.sendEmptyMessageDelayed(MSG_ID,1000);
                    }
                    break;
                default:
                    break;
            }
        }
    };
    // Used to load the 'native-lib' library on application startup.

//以下兩種方式載入lib都是可以的
    static {
//        System.loadLibrary("native-lib");
        Runtime.getRuntime().loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        tv = (TextView) findViewById(R.id.sample_text);

    }

    @Override
    protected void onResume() {
        super.onResume();

        xiaoming = new Person(1, "xiaoming");
        Person hello = new Person(3, "hello");
        sex = "boy";
        xiaohua = new Person(4, "xiaohua");
        xiaohua.setSchool("beijing xiaoxue");

        Log.d(TAG, "sex=" + sex + ",getSchool=" + xiaohua.getSchool()
                + ",xiaohua =" + xiaohua.toString() + ",xiaoming=" + xiaoming.toString());

        getPersion(hello);

        tv.setText(xiaoming.toString() + hello.toString());
        Log.d(TAG, "after getPersion  sex=" + sex + ",getSchool=" + xiaohua.getSchool()
                + ",xiaohua =" + xiaohua.toString() + ",xiaoming=" + xiaoming.toString());

        setPersionInfo(xiaoming);

        Log.d(TAG, "after setPersionInfo  sex=" + sex + ",getSchool=" + xiaohua.getSchool()
                + ",xiaohua =" + xiaohua.toString() + ",xiaoming=" + xiaoming.toString());

        setListener(new StateListener() {
            @Override
            public void onStateChange(int code, String msg) {
                Log.d(TAG, "onStateChange  code=" + code + ",msg=" + msg);
            }

            @Override
            public void onModifyValue(Person person) {
                Log.d(TAG, "onModifyValue  person=" + person.toString());
            }
        });

        msg_code = 0;
        mHandler.sendEmptyMessageDelayed(MSG_ID,1000);


    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mHandler.hasMessages(MSG_ID)){
            mHandler.removeMessages(MSG_ID);
        }
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    public native void getPersion(Person person);

    public static native void setPersionInfo(Person persio);

    public native void setListener(StateListener listener);

    public native void callListerner(int code);

}

​
#include <jni.h>
#include <string>
#include "mylog.h"

JavaVM *g_javaVM;
jobject g_listerner;
int mNeedDetach;

#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jstring JNICALL Java_com_test_myjnitest_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject jthis) {
    std::string hello = "Hello from C++ ";

    return env->NewStringUTF(hello.c_str());
}

JNIEXPORT void JNICALL Java_com_test_myjnitest_MainActivity_getPersion(
        JNIEnv *env, jobject jthis, jobject jobj) {

    if (NULL == env || NULL == jthis || NULL == jobj) {
        return;
    }

//###################獲取MainActivity類的例項變數#########################
    // 1.獲取MainActivity類Class引用
    jclass jc = env->GetObjectClass(jthis);
    if (NULL == jc) {
        return;
    }
    // 2. 獲取MainActivity類例項變數xiaoming的屬性ID
    jfieldID jfieldID1 = env->GetFieldID(jc, "xiaoming", "Lcom/test/myjnitest/Person;");
    // 3. 獲取MainActivity類例項變數xiaoming的值
    jobject jxiaoming = env->GetObjectField(jthis, jfieldID1);

    // 1.獲取Person類的Class引用
    jclass jPerson = env->GetObjectClass(jxiaoming);
    if (NULL == jPerson) {
        return;
    }
    // 2.獲取Person類例項變數xiaoming的age屬性ID
    jfieldID jAgeID = env->GetFieldID(jPerson, "age", "I");
    // 3.獲取Person類例項變數xiaoming的age的值
    jint jAge = env->GetIntField(jxiaoming, jAgeID);

    // 2.獲取Person類例項變數xiaoming的name屬性ID
    jfieldID jNameID = env->GetFieldID(jPerson, "name", "Ljava/lang/String;");
    // 3.獲取Person類例項變數xiaoming的name的值
    jstring jName = (jstring) env->GetObjectField(jxiaoming, jNameID);
    //轉化為可以輸出的char*
    const char *cName = env->GetStringUTFChars(jName, 0);
    LOGD("########## i = %d,name=%s", jAge, cName);
    //釋放剛才申請的char*
    env->ReleaseStringUTFChars(jName, cName);
    //改變cpp裡的jage 不會影響java裡的值
    jAge = 10;
    //給改變java檔案的age值
    env->SetIntField(jxiaoming, jAgeID, 20);
    LOGD("########## i = %d", jAge);
    //
    jName = env->NewStringUTF("JNI_xiaoming");
    env->SetObjectField(jxiaoming, jNameID, jName);

//###############獲取當前介面函式傳輸過來的形參例項變數#############################

    //以下兩行都可以獲取到該類的class引用
    jclass jclass1 = env->FindClass("com/test/myjnitest/Person");
//    jclass jclass1 = env->GetObjectClass(jobj);

    if (NULL == jclass1) {
        return;
    }
    //通過該類的屬性獲取age的值
    jfieldID jageId = env->GetFieldID(jclass1, "age", "I");
    jint jage = env->GetIntField(jobj, jageId);
    //通過該類的getAge獲取age的值
    jmethodID jageMethodId = env->GetMethodID(jclass1, "getAge", "()I");
    jint jageM = env->CallIntMethod(jobj, jageMethodId);

    jmethodID jnameMethodId = env->GetMethodID(jclass1, "getName", "()Ljava/lang/String;");
    jstring jnameM = (jstring) env->CallObjectMethod(jobj, jnameMethodId);

    const char *cNameM = env->GetStringUTFChars(jnameM, 0);
    LOGD("########## getPersion jni jage=%d,jageM=%d,cNameM=%s", jage, jageM, cNameM);
    env->ReleaseStringUTFChars(jnameM, cNameM);

//    jmethodID jSetAgeId = env->GetMethodID(jclass1,"setAge","(I)V");
//    env->CallVoidMethod(jobj,jSetAgeId,30);

    env->SetIntField(jobj, jageId, 40);

    jmethodID jSetNameID = env->GetMethodID(jclass1, "setName", "(Ljava/lang/String;)V");
    env->CallVoidMethod(jobj, jSetNameID, env->NewStringUTF("JNI_hello"));

//##############釋放申請的引用#############################
    env->DeleteLocalRef(jclass1);
    env->DeleteLocalRef(jPerson);
    env->DeleteLocalRef(jc);
    env->DeleteLocalRef(jxiaoming);
}
//獲取static變數或者靜態方法,使用帶有static的方法獲取即可
JNIEXPORT void JNICALL Java_com_test_myjnitest_MainActivity_setPersionInfo(
        JNIEnv *env,
        jclass jclass1, jobject jobj) {
    if (NULL == jclass1 || NULL == env || NULL == jobj) {
        return;
    }
    jfieldID jSexId = env->GetStaticFieldID(jclass1, "sex", "Ljava/lang/String;");
    jstring jSex = (jstring) env->GetStaticObjectField(jclass1, jSexId);
    const char *cSex = env->GetStringUTFChars(jSex, 0);
    LOGD("########## Sex = %s", cSex);
    env->ReleaseStringUTFChars(jSex, cSex);

    env->SetStaticObjectField(jclass1, jSexId, env->NewStringUTF("girl"));


    jfieldID jXiaohuaId = env->GetStaticFieldID(jclass1, "xiaohua", "Lcom/test/myjnitest/Person;");
    jobject jXiaohua = env->GetStaticObjectField(jclass1, jXiaohuaId);

    jclass jPersion = env->GetObjectClass(jXiaohua);
    if (NULL == jPersion) {
        return;
    }

    jfieldID jSchoolId = env->GetStaticFieldID(jPersion, "school", "Ljava/lang/String;");
    jstring jSchool = (jstring) env->GetStaticObjectField(jPersion, jSchoolId);
    const char *cSchool = env->GetStringUTFChars(jSchool, 0);
    LOGD("########## cSchool = %s", cSchool);
    env->ReleaseStringUTFChars(jSchool, cSchool);

    env->SetStaticObjectField(jPersion, jSchoolId, env->NewStringUTF("shanghai xiaoxue"));

    jfieldID jageId = env->GetFieldID(jPersion, "age", "I");
    jint jage = env->GetIntField(jXiaohua, jageId);

    jmethodID jNameMethodID = env->GetMethodID(jPersion, "getName", "()Ljava/lang/String;");
    jstring jNameM = (jstring) env->CallObjectMethod(jXiaohua, jNameMethodID);
    const char *cName = env->GetStringUTFChars(jNameM, 0);
    LOGD("########## jage =%d, cName = %s", jage, cName);
    env->ReleaseStringUTFChars(jNameM, cName);

    env->SetIntField(jXiaohua, jageId, 8);

    jmethodID jSetNameMethodId = env->GetMethodID(jPersion, "setName", "(Ljava/lang/String;)V");
    env->CallVoidMethod(jXiaohua, jSetNameMethodId, env->NewStringUTF("xiaohua from JNI"));

    jclass jObjClass = env->GetObjectClass(jobj);
    if (NULL == jObjClass) {
        return;
    }
    jfieldID jAgeid2 = env->GetFieldID(jObjClass, "age", "I");
    jint jage2 = env->GetIntField(jobj, jAgeid2);

    jmethodID jgetNameID2 = env->GetMethodID(jObjClass, "getName", "()Ljava/lang/String;");
    jstring jgetName2 = (jstring) env->CallObjectMethod(jobj, jgetNameID2);
    const char *cgetName2 = env->GetStringUTFChars(jgetName2, 0);
    LOGD("########## jage2 =%d, cgetName2 = %s", jage2, cgetName2);
    env->ReleaseStringUTFChars(jgetName2, cgetName2);

    jmethodID jSetNameID2 = env->GetMethodID(jObjClass, "setName", "(Ljava/lang/String;)V");
    env->CallVoidMethod(jobj, jSetNameID2,
                        env->NewStringUTF("JNI_xiaoming from JNI setPersionInfo"));

    env->DeleteLocalRef(jXiaohua);
    env->DeleteLocalRef(jPersion);

}

JNIEXPORT void JNICALL Java_com_test_myjnitest_MainActivity_setListener(
        JNIEnv *env, jobject jthis, jobject jlisterner) {
    if (NULL == env || NULL == jthis || NULL == jlisterner) {
        return;
    }
    env->GetJavaVM(&g_javaVM);
    if (NULL == g_javaVM) {
        return;
    }
    g_listerner = env->NewGlobalRef(jlisterner);

}

JNIEnv *getEnvFuc() {
    JNIEnv *env;
    int getEnvStat = g_javaVM->GetEnv((void **) &env, JNI_VERSION_1_6);
    if (getEnvStat == JNI_EDETACHED) {
        if (g_javaVM->AttachCurrentThread(&env, NULL) != 0) {
            return NULL;
        }
        mNeedDetach = JNI_TRUE;
    }
    return env;
}

void ReleaseEnvFuc() {
    if (mNeedDetach) {
        g_javaVM->DetachCurrentThread();
    }
}

void listerner_onStateChange(int code) {
    JNIEnv *env = getEnvFuc();
    if (NULL == env) {
        return;
    }

    jclass jclass1 = env->GetObjectClass(g_listerner);
    if (NULL == jclass1) {
        return;
    }

    jmethodID onstatechageID = env->GetMethodID(jclass1, "onStateChange", "(ILjava/lang/String;)V");

    env->CallVoidMethod(g_listerner, onstatechageID, code,
                        env->NewStringUTF("listerner_onStateChange"));


    env->DeleteLocalRef(jclass1);
    jclass1 = NULL;

    ReleaseEnvFuc();

    env = NULL;
}

void listerner_onModifyValue(int age) {
    JNIEnv *env = getEnvFuc();
    if (NULL == env) {
        return;
    }

    jclass jclass1 = env->GetObjectClass(g_listerner);
    if (NULL == jclass1) {
        return;
    }

    jmethodID onModifyValueID = env->GetMethodID(jclass1, "onModifyValue",
                                                 "(Lcom/test/myjnitest/Person;)V");

    //以下是生成一個java的Person類物件
    jclass jArgclass = env->FindClass("com/test/myjnitest/Person");
    jmethodID initId = env->GetMethodID(jArgclass, "<init>", "(ILjava/lang/String;)V");
    jobject jPerson = env->NewObject(jArgclass, initId, age,
                                     env->NewStringUTF("listerner_onModifyValue"));

    env->CallVoidMethod(g_listerner, onModifyValueID, jPerson);

    env->DeleteLocalRef(jPerson);
    env->DeleteLocalRef(jArgclass);
    env->DeleteLocalRef(jclass1);
    jclass1 = NULL;

    ReleaseEnvFuc();

    env = NULL;
}

JNIEXPORT void JNICALL Java_com_test_myjnitest_MainActivity_callListerner(
        JNIEnv *env, jobject jthis, jint jcode) {
    if (NULL == env || NULL == jthis) {
        return;
    }
    listerner_onStateChange(jcode);
    listerner_onModifyValue(jcode + 20);

}


#ifdef __cplusplus
}
#endif