[Android初级]NDK入门体验の方法调用

本文属于自我复习,内容重复请勿见怪

如何在android应用的自定义底层C中调用java的代码?这是本次自我复习的计划。

首先,我得创建一个demo,结构如下:

1.创建一个接口类NativeDataProvider,他的作用是调用c方法,然后回调java方法

public class NativeDataProvider {static final String TAG = "NativeDataProvider";private Context context;public NativeDataProvider(Context context){this.context = context;}//调用C中的代码public native void callCCode();public native int callCAdd(int i,int j);public native void callCPrintString();//在C中调用java中的org.jan.ndk.example.NativeDataProvider无参方法helloFrmJavapublic void helloFromJava(){Log.i(TAG, "hello from java!");Toast.makeText(context, "hello from java", Toast.LENGTH_SHORT).show();}//在C中调用参数为string的方法public void printString(String str){Log.i(TAG, "[from java]:"+str);Toast.makeText(context, "printString->str:"+str, Toast.LENGTH_SHORT).show();}//在c中调用int参数的方法public int add(int i,int j){int result = i+j;Log.i(TAG, "result is"+result);Toast.makeText(context, "add->result="+result, Toast.LENGTH_SHORT).show();return result;}}2.创建Android.mkLOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := jni_demoLOCAL_SRC_FILES := jni_demo.c#增加log库LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY)3.创建jni,也就是c代码,之前先创建NativeDataProvider的头文件,到项目目录/bin/classes下,调用javah org.jan.ndk.example.NativeDataProvider

就会生成org_jan_ndk_example_NativeDataProvider.h

/* DO NOT EDIT THIS FILE – it is machine generated */#include <jni.h>/* Header for class org_jan_ndk_example_NativeDataProvider */#ifndef _Included_org_jan_ndk_example_NativeDataProvider#define _Included_org_jan_ndk_example_NativeDataProvider#ifdef __cplusplusextern "C" {#endif/* * Class:org_jan_ndk_example_NativeDataProvider * Method: callCCode * Signature: ()V */JNIEXPORT void JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCCode (JNIEnv *, jobject);/* * Class:org_jan_ndk_example_NativeDataProvider * Method: callCAdd * Signature: (II)I */JNIEXPORT jint JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCAdd (JNIEnv *, jobject, jint, jint);/* * Class:org_jan_ndk_example_NativeDataProvider * Method: callCPrintString * Signature: ()V */JNIEXPORT void JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCPrintString (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif

其中看到有Signature:()V 这样类似的 就是 方法签名。

例如:

har* classname = "org/jan/ndk/example/NativeDataProvider";jclass dpclazz = (*env)->FindClass(env, classname);

这是通过jnienv指针获取class对象。

jmethodID methodID = (*env)->GetMethodID(env, dpclazz, "helloFromJava", "()V");

GetMethodID指 从java中获取定义好的method方法,第二个参数是class对象,第三个参数是方法名,第四个是方法签名(可以从头文件中看Signature)

看方法签名的方法: 进入项目\bin\classes 下,,命令:javap -s org.jan.ndk.example.NativeDataProvider

"()V"的大概意思就是 括号内没有参数,就是没有入参,V就是void无返回值。

下面是C主要代码(具体请看注释):

#include "org_jan_ndk_example_NativeDataProvider.h"#include <string.h>#include <android/log.h>#define LOG_TAG "System.out"#define LOGD(…) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)#define LOGI(…) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)JNIEXPORT void JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCCode (JNIEnv * env, jobject obj){//调用NativeDataProvider对象中的helloFromJava()方法//获取到某个对象, 获取对象中的方法, 调用获取到的方法LOGI("in code");//NativeDataProvider完整类名 org.jan.ndk.example.NativeDataProviderchar* classname = "org/jan/ndk/example/NativeDataProvider";jclass dpclazz = (*env)->FindClass(env, classname);if(dpclazz == 0)LOGI("org.jan.ndk.example.NativeDataProvider.class not find !!!");elseLOGI("org.jan.ndk.example.NativeDataProvider.class find !!!");//使用jni.h中提供的GetMethodID方法, 获取jmethodID, 传入参数 ①JNIEnv指针 ②Class对象 ③ 方法名 ④方法签名, 在这里方法名和方法签名确定一个方法, 方法签名就是方法的返回值 与 参数的唯一标示;//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的methodjmethodID methodID = (*env)->GetMethodID(env, dpclazz, "helloFromJava", "()V");if(methodID == 0)LOGI("method helloFromJava not find !!!");elseLOGI("method helloFromJava find !!!");/* * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, …); * 参数介绍 : 后面的 … 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列 */LOGI("before call method");(*env)->CallVoidMethod(env, obj, methodID);LOGI("after call method");}JNIEXPORT void JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCPrintString (JNIEnv *env, jobject obj){//调用DataProvider对象中的helloFromJava()方法//获取到某个对象, 获取对象中的方法, 调用获取到的方法LOGI("in code");//NativeDataProvider完整类名 org.jan.ndk.example.NativeDataProviderchar* classname = "org/jan/ndk/example/NativeDataProvider";jclass dpclazz = (*env)->FindClass(env, classname);if(dpclazz == 0)LOGI("class not find !!!");elseLOGI("class find !!!");//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的methodjmethodID methodID = (*env)->GetMethodID(env, dpclazz, "printString", "(Ljava/lang/String;)V");if(methodID == 0)LOGI("method not find !!!");elseLOGI("method find !!!");/* * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, …); * 参数介绍 : 后面的 … 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列 */LOGI("before call method");(*env)->CallVoidMethod(env, obj, methodID, (*env)->NewStringUTF(env, "printString method callback success!!"));LOGI("after call method");}/* * 实际开发的情况 * C代码工程师给我们 first.h first.c , 我们只需要将first.h引入, 然后就可以使用其中的方法了 */JNIEXPORT jint JNICALL Java_org_jan_ndk_example_NativeDataProvider_callCAdd(JNIEnv *env, jobject obj, jint a, jint b){//调用DataProvider对象中的helloFromJava()方法//获取到某个对象, 获取对象中的方法, 调用获取到的方法LOGI("in code test_add=>");//NativeDataProvider完整类名 org.jan.ndk.example.NativeDataProviderchar* classname = "org/jan/ndk/example/NativeDataProvider";jclass dpclazz = (*env)->FindClass(env, classname);if(dpclazz == 0)LOGI("class not find !!!");elseLOGI("class find !!!");//参数介绍 : 第二个参数是Class对象, 第三个参数是方法名,第四个参数是方法的签名, 获取到调用的methodjmethodID methodID = (*env)->GetMethodID(env, dpclazz, "add", "(II)I");if(methodID == 0)LOGI("method not find !!!");elseLOGI("method find !!!");/* * 调用方法 void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, …); * 参数介绍 : 后面的 … 是可变参数, 如果该返回值void的方法有参数, 就将参数按照次序排列 */return (*env)->CallIntMethod(env, obj, methodID, a,b);}

4.编译jni,在demo目录下手动执行ndk-build

如果说对云南有进一步的了解的话就是鲜花。

[Android初级]NDK入门体验の方法调用

相关文章:

你感兴趣的文章:

标签云: