• Android之NDK编程(JNI)


    转自:http://www.cnblogs.com/xw022/archive/2011/08/18/2144621.html

    NDK编程入门--C回调JAVA方法

     

    一、主要流程

    1、  新建一个测试类TestProvider.java

    a)         该类提供了2个方法

    b)        一个静态的方法,一个非静态的方法

    2、  JNI中新建Provider.c

    a)         该文件中需要把Java中的类TestProvider映射到C中

    b)        把TestProvider的两个方法映射到C中

    c)         新建TestProvider 对象

    d)        调用两个方法

    3、  Android 上层 调用 JNI层

    4、  JNI层调用C层

    5、  C 层调用 Java 方法

    二、设计实现

    1. 关键代码说明

    C中定义映射的类、方法、对象

    jclass TestProvider;

    jobject mTestProvider;

    jmethodID getTime;

    jmethodID sayHello;

    中映射 

           TestProvider = (*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider");

    C中新建对象

           jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, TestProvider,"<init>", "()V");

    TestProvider mTestProvider = (*jniEnv)->NewObject(jniEnv, TestProvider,construction_id);

    中映射方法

           静态:

    getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");

           非静态:

    sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello","(Ljava/lang/String;)V");

    中调用 Java的 方法

           静态:

    (*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime);

           非静态:

    (*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);

    注意 GetXXXMethodID  和 CallXXXMethod 。

    第一个XXX 表示的是映射方法的类型,如: 静态 跟非静态

    第二个 XXX 表示 调用方法的返回值 ,如:Void,Object,等等。(调用静态方法的时候Call后面要加Static)

    详细 映射方法 和 调用方法 请参考JNI文档

    3.Java 上层 关键代码

      TestProvider.Java 的两个方法

     
    package com.duicky;

    publicclass TestProvider {

    publicstatic String getTime() {
    LogUtils.printWithSystemOut( "Call From C Java Static Method" );
    LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Static Method" );
    return String.valueOf(System.currentTimeMillis());
    }

    publicvoid sayHello(String msg) {
    LogUtils.printWithSystemOut("Call From C Java Not Static Method :"+ msg);
    LogUtils.toastMessage(MainActivity.mContext, "Call From C Java Not Static Method :"+ msg);
    }

    }
     

    3、Android.mk 文件 关键代码  

     
    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
    LOCAL_LDLIBS +=-L$(SYSROOT)/usr/lib -llog


    LOCAL_MODULE := NDK_04
    LOCAL_SRC_FILES :=
    CToJava.c
    Provider.c

    include $(BUILD_SHARED_LIBRARY)
     

    4、      JNI文件夹下文件

      provider.h

      

    #include <string.h>
    #include <jni.h>

    void GetTime() ;
    void SayHello();

      

      Provider.c 

     
    #include "Provider.h"
    #include <android/log.h>

    extern JNIEnv* jniEnv;

    jclass TestProvider;
    jobject mTestProvider;
    jmethodID getTime;
    jmethodID sayHello;

    int GetProviderInstance(jclass obj_class);

    /**
    * 初始化 类、对象、方法
    */
    int InitProvider() {

    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 1" );

    if(jniEnv == NULL) {
    return0;
    }

    if(TestProvider == NULL) {
    TestProvider = (*jniEnv)->FindClass(jniEnv,"com/duicky/TestProvider");
    if(TestProvider == NULL){
    return-1;
    }
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 2 ok" );
    }

    if (mTestProvider == NULL) {
    if (GetProviderInstance(TestProvider) !=1) {
    (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);
    return-1;
    }
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 3 ok" );
    }

    if (getTime == NULL) {
    getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");
    if (getTime == NULL) {
    (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);
    (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider);
    return-2;
    }
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 4 ok" );
    }

    if (sayHello == NULL) {
    sayHello = (*jniEnv)->GetMethodID(jniEnv, TestProvider, "sayHello","(Ljava/lang/String;)V");
    if (sayHello == NULL) {
    (*jniEnv)->DeleteLocalRef(jniEnv, TestProvider);
    (*jniEnv)->DeleteLocalRef(jniEnv, mTestProvider);
    (*jniEnv)->DeleteLocalRef(jniEnv, getTime);
    return-3;
    }
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 5 ok" );
    }

    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "InitProvider Begin 6" );
    return1;

    }

    int GetProviderInstance(jclass obj_class) {

    if(obj_class == NULL) {
    return0;
    }

    jmethodID construction_id = (*jniEnv)->GetMethodID(jniEnv, obj_class,
    "<init>", "()V");

    if (construction_id ==0) {
    return-1;
    }

    mTestProvider = (*jniEnv)->NewObject(jniEnv, obj_class,
    construction_id);

    if (mTestProvider == NULL) {
    return-2;
    }

    return1;
    }

    /**
    * 获取时间 ---- 调用 Java 方法
    */
    void GetTime() {
    if(TestProvider == NULL || getTime == NULL) {
    int result = InitProvider();
    if (result !=1) {
    return;
    }
    }

    jstring jstr = NULL;
    char* cstr = NULL;
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "GetTime Begin" );
    jstr = (*jniEnv)->CallStaticObjectMethod(jniEnv, TestProvider, getTime);
    cstr = (char*) (*jniEnv)->GetStringUTFChars(jniEnv,jstr, 0);
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "Success Get Time from Java , Value = %s",cstr );
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "GetTime End" );

    (*jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, cstr);
    (*jniEnv)->DeleteLocalRef(jniEnv, jstr);
    }

    /**
    * SayHello ---- 调用 Java 方法
    */
    void SayHello() {
    if(TestProvider == NULL || mTestProvider == NULL || sayHello == NULL) {
    int result = InitProvider() ;
    if(result !=1) {
    return;
    }
    }

    jstring jstrMSG = NULL;
    jstrMSG =(*jniEnv)->NewStringUTF(jniEnv, "Hi,I'm From C");
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "SayHello Begin" );
    (*jniEnv)->CallVoidMethod(jniEnv, mTestProvider, sayHello,jstrMSG);
    __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "SayHello End" );

    (*jniEnv)->DeleteLocalRef(jniEnv, jstrMSG);
    }
     

      CToJava.c

     
    #include <string.h>
    #include <android/log.h>
    #include <jni.h>
    #include "Provider.h"

    JNIEnv* jniEnv;

    /**
    * Java 中 声明的native getTime 方法的实现
    */
    void Java_com_duicky_MainActivity_getTime(JNIEnv* env, jobject thiz)
    {

    if(jniEnv == NULL) {
    jniEnv = env;
    }

    GetTime();
    }

    /**
    * Java 中 声明的native sayHello 方法的实现
    */
    void Java_com_duicky_MainActivity_sayHello(JNIEnv* env, jobject thiz)
    {
    if (jniEnv == NULL) {
    jniEnv = env;
    }

    SayHello();
    }
     

    三.Java 方法映射到C中的签名

      签名是由两部分组成,"()" 里面代表的是方法的参数,后面外面的部分代表的是该方法的返回值

        public int test3(int i) { return i;}          (I)I

      基本数据类型对应关系如表:

        

        其实仔细看看发现就是对应java类型的首字母拉, Boolean 比较特殊, 对应的是 Z , Long 对应J

      引用数据类型:比较麻烦点,以“L”开头,以“;”结束,中间对应的是该类型的路径

           如:String : Ljava/lang/String;

                  Object: Ljava/lang/Object;

           自定义类 Cat  对应  package com.duicky;

                  Cat : Lcom/duicky/Cat;

      数组表示:  数组表示的时候以“[” 为标志,一个“[”表示一维数组

           如:int [] :[I

                  Long[][]  : [[J

                  Object[][][] : [[[Ljava/lang/Object;

    字符 Java类型 C类型

    V      void            void
    Z       jboolean     boolean
    I        jint              int
    J       jlong            long
    D      jdouble       double
    F      jfloat            float
    B      jbyte            byte
    C      jchar           char
    S      jshort          short

    数组则以"["开始,用两个字符表示

    [I       jintArray      int[]
    [F     jfloatArray    float[]
    [B     jbyteArray    byte[]
    [C    jcharArray    char[]
    [S    jshortArray   short[]
    [D    jdoubleArray double[]
    [J     jlongArray     long[]
    [Z    jbooleanArray boolean[]

    输入命令: javap –s  加上你要查看方法签名的 类 名

           如: javap –s Test  结果就显示出我们想要的签名了。、

    四、C调用Java注意点

    1.   映射java 方法时 对应的签名 

       getTime = (*jniEnv)->GetStaticMethodID(jniEnv, TestProvider, "getTime","()Ljava/lang/String;");

    2.       映射方法的时候需要区别静态和非静态GetStaticMethodID,GetMethodID

    3.     调用的时候也需要区分CallStaticObjectMethod,CallVoidMethod 而且还需要区分返回值类型

     
     
    转载http://www.cnblogs.com/luxiaofeng54/archive/2011/08/18/2143977.html
  • 相关阅读:
    Sum Root to Leaf Numbers深度优先计算路径和
    Path Sum II深度优先找路径
    动态和静态链接库
    C/C++变量
    搜索
    基本格式
    随机数生成函数
    珍惜生命,我用Python 。今天开始学习Python
    在windows里hexo 博客创建步骤
    作为一个程序员,什么是脚本。必须要理解
  • 原文地址:https://www.cnblogs.com/colife/p/3805380.html
Copyright © 2020-2023  润新知