Android开发,JNI,NDK,C++和java代码互相调用方法

文章目录

  • Android开发,JNI,NDK,C++和java代码互相调用方法
    • 1.java,jni,c数据类型
    • 2.jni日志输出
    • 3.函数调用

Android开发,JNI,NDK,C++和java代码互相调用方法

1.java,jni,c数据类型

java的数据类型不能直接给c使用,要通过jni转换。

比如String,要通过jni的jstring转换成c语言的char *,其他数据类型也是一样

实践

java层代码

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    private static final String TAG = "MainActivity";
    private String test = "test";

    public native String stringFromJNI();

    public native void test();

    private double num = 1;
    private final double num2 = 2;

    public native void doubleFromJNI();

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

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        Log.e(TAG, "onCreate: ");
        test();
        Log.e(TAG, "onCreate: 修改前 " + num2);
        doubleFromJNI();
        Log.e(TAG, "onCreate: 修改后 " + num2);

    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
}

jni

#include 
#include 

#include 

#define TAG "testLog"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
//代码采用C语言编译
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_test(JNIEnv *env, jobject jobject1) {


}extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_doubleFromJNI(JNIEnv *env, jobject thiz) {
    jclass test = env->GetObjectClass(thiz);
//    jfieldID num = env->GetFieldID(test, "num", "D");
//
//    env->SetDoubleField(thiz,num, 444.5);


    jfieldID num2 = env->GetFieldID(test, "num2", "D");
    env->SetDoubleField(thiz, num2, 5555.5);

    LOGD("SSSSSSSSSSSSSS %d\n", 1312);
}

运行一下看看修改的num2的值

Android开发,JNI,NDK,C++和java代码互相调用方法_第1张图片

这个是java和jni通信的桥梁。

JNIEnv

看他源码

Android开发,JNI,NDK,C++和java代码互相调用方法_第2张图片

//当前语言是c++、
#if defined(__cplusplus)
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
#else
//当前语言是c语言
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
#endif

指的是我们这个文件的后缀

Android开发,JNI,NDK,C++和java代码互相调用方法_第3张图片

最终

都是访问的这个结构体指针,C语言的

Android开发,JNI,NDK,C++和java代码互相调用方法_第4张图片

如果方法是静态的就是jclass,否则就是对象实例,

Android开发,JNI,NDK,C++和java代码互相调用方法_第5张图片

Android开发,JNI,NDK,C++和java代码互相调用方法_第6张图片

最终jni会打包到apk中成为一个so库

Android开发,JNI,NDK,C++和java代码互相调用方法_第7张图片

2.jni日志输出

日志库

#include 

#define TAG "testLog"

#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__);

Android开发,JNI,NDK,C++和java代码互相调用方法_第8张图片

运行

Android开发,JNI,NDK,C++和java代码互相调用方法_第9张图片

3.函数调用

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

    private static final String TAG = "MainActivity";
    private String test = "test";

    public native String stringFromJNI();

    public native void test();

    private double num = 1;
    private double num2 = 2;

    public native void doubleFromJNI();
    //jni调用它
    public int addNum(int a, int b) {
        Log.e(TAG, "addNum: ");
        return a + b;
    }
    //
    public native void testAddNum();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
        Log.e(TAG, "onCreate: ");
        test();
        Log.e(TAG, "onCreate: 修改前 " + num2);
        doubleFromJNI();
        Log.e(TAG, "onCreate: 修改后 " + num2);
        testAddNum();
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
}

声明一个java函数一个jni函数

Android开发,JNI,NDK,C++和java代码互相调用方法_第10张图片

在java中调用我们的jni函数

Android开发,JNI,NDK,C++和java代码互相调用方法_第11张图片

jni中再反调用我们的java函数

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testAddNum(JNIEnv *env, jobject thiz) {
    jclass jclass1 = env->GetObjectClass(thiz);
    jmethodID add = env->GetMethodID(jclass1, "addNum", "(II)I");
    int jint = env->CallIntMethod(thiz, add, 2, 3);
    LOGD("============%d\n", jint);
}

输出

Android开发,JNI,NDK,C++和java代码互相调用方法_第12张图片

字符串函数

Android开发,JNI,NDK,C++和java代码互相调用方法_第13张图片

jni调用java字符串函数

extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_MainActivity_testAddNum(JNIEnv *env, jobject thiz) {
    /*jclass jclass1 = env->GetObjectClass(thiz);
    jmethodID add = env->GetMethodID(jclass1, "addNum", "(II)I");
    int jint = env->CallIntMethod(thiz, add, 2, 3);
    LOGD("============%d\n", jint);*/
    jclass jclass1 = env->GetObjectClass(thiz);
    jmethodID jmethodId = env->GetMethodID(jclass1, "getTestString",
                                           "(Ljava/lang/String;I)Ljava/lang/String;");
    jstring va = env->NewStringUTF("22222");
    jstring rrr = (jstring) env->CallObjectMethod(thiz, jmethodId, va, 222);
    const char *string = env->GetStringUTFChars(rrr,NULL);
    LOGD("==============%s\n", string);
}

Android开发,JNI,NDK,C++和java代码互相调用方法_第14张图片

你可能感兴趣的:(Android进阶训练营,android,c++,java)