许多成熟的C引擎要移植到Android 平台上使用 , 一般都会 提供 一些接口, 让Android sdk 和 jdk 实现。

下文将会介绍 C 如何 通过 JNI 层调用 Java 的静态和非静态方法。

1、主要流程

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 方法

2、设计实现

1、界面设计如下:

老样子,很搓,不过实用,嘿嘿

代码不在这贴出了,有需要的兄弟直接到文章结束部分下载。

2、      关键代码说明

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

jclass TestProvider;

jobject mTestProvider;

jmethodID getTime;

jmethodID sayHello;

C 中映射

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);

C 中映射方法

静态:

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

非静态:

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

C 中调用 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;
 
/**
 *
 *
 * @author luxiaofeng <454162034@qq.com>
 *
 */
public class TestProvider {
 
    public static 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());
    }
 
    public void 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);
    }
 
}

  

4、      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)

  

老样子,不说了,你懂的。 如果不懂,嘎嘎,那就请点击Android.mk 文件 简介

5、      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) {
        return 0;
    }
 
    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" );
    return 1;
 
}
 
int GetProviderInstance(jclass obj_class) {
 
    if(obj_class == NULL) {
        return 0;
    }
 
    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;
    }
 
    return 1;
}
 
/**
 * 获取时间 ---- 调用 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();
}

  

3、运行效果

1、点击 “C调用java静态方法”按钮

C成功调用了Java中的getTime 方法,通过C方法打印出上层调用得到的时间,并且上层成功吐司出调用信息出来。

2、点击 “C调用java非静态方法”按钮

C成功调用了sayHello 方法, 并成功接收到 C 传递的参数,和 吐司出相对应的信息

4、C调用Java注意点

a)
C 映射java 方法时 对应的签名

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

故事情节还没发展这么快,下一章才会专门介绍下这个签名的使用

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

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

有不理解的兄弟请留言,个人技术有限,有讲错的地方请大牛们指出,讲的不够全面的请多多包涵,谢谢,

点击下载源码
C调用Java例子

本文出自 duicky 博客 , 转载请注明出处 http://www.cnblogs.com/luxiaofeng54/archive/2011/08/17/2142000.html

基于 Android NDK 的学习之旅----- C调用Java的更多相关文章

  1. 【转】基于 Android NDK 的学习之旅-----数据传输(引用数据类型)

    原文网址:http://www.cnblogs.com/luxiaofeng54/archive/2011/08/20/2147086.html 基于 Android NDK 的学习之旅-----数据 ...

  2. 基于 Android NDK 的学习之旅-----环境搭建

    工欲善其事 必先利其器 , 下面介绍下 Eclipse SDK NDK Cygwin CDT 集成开发环境的搭建. 1.Android 开发环境搭建 Android开发环境搭建不是重点,相信看此文章的 ...

  3. 基于 Android NDK 的学习之旅-----序言

    前些日子做了个Android项目, 引擎层 用C的, 准备写这个系类的文章,借此跟朋友来分享下我NDK开放的经验以及自己知识的总结和备忘.希望能给需要这方面资料的朋友提供一定的帮助. 主要涉及到:   ...

  4. 基于 Android NDK 的学习之旅-----HelloWorld

    Hello World作为所有编程语言的起始阶段,占据着无法改变的地位,所有中/英/法/德/美……版本的编程教材中,hello world总是作为第一个TEST记录于书本之中,所有的编程第一步就在于此 ...

  5. 基于 Android NDK 的学习之旅-----JNI LOG 打印

    程序都是调出来的. 下面我介绍下JNI层的log打印方法的使用,类似与Android sdk提供的log 1.Android 应用层 MainActivity.java 主要功能代码 a)       ...

  6. 基于 Android NDK 的学习之旅-----数据传输(引用数据类型)

    接着上篇文章继续讲.主要关于引用类型的数据传输,本文将介绍字符串传输和自定义对象的传输. 1.主要流程 1.  String 字符串传输 a)         上层定义一个native的方法,需要一个 ...

  7. 基于 Android NDK 的学习之旅-----Java 调用C

    随便谈谈为什么要Java调用C 吧: 我认为: 1.  有些公司开发Android项目的时候, 许多组件功能可能是C中已经实现了,所以我们没必要同样的功能又在java中实现一遍.例如我之前做的一个项目 ...

  8. 基于 Android NDK 的学习之旅-----Android.mk 介绍

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

  9. 基于 Android NDK 的学习之旅-----资源释放

    做上一个项目的时候因为与C引擎交互频繁,有时候会突然莫名其妙的的整个应用程序直接挂掉.因为我是学Java 开始的,所以对主动释放内存没多大概念(GC直接帮忙回收),后查询原因才知道是因为JNI 有些对 ...

随机推荐

  1. js的数据类型和typeof数据类型

    js的数据类型:number,string,null,undefined,Boolean,object typeof数据类型:number,string,object,function,undefin ...

  2. NuGet 使用及dll管理

    NuGet学习笔记(1)——初识NuGet及快速安装使用 作者: 懒惰的肥兔  来源: 博客园  发布时间: 2012-05-20 21:33  阅读: 53168 次  推荐: 33   原文链接  ...

  3. 【例题 8-10 UVA - 714】 Copying Books

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 二分最后的最大值的最小值. 得到ans 然后从后往前尽量划分. 如果发现不够分成k个. 那么就从第一个开始接着分restk个(每隔1 ...

  4. html中的瀑布流是什么

    html中的瀑布流是什么 一.总结 1.瀑布流: 从左往右排列,哪一列现在的总高度最小,就优先排序把item(单元格)放在这一列.这样排完所有的单元格后,可以保证每一列的总高度都相差不大 2.看效果图 ...

  5. 关于python中数组的问题,序列格式转换

    https://blog.csdn.net/sinat_34474705/article/details/74458605?utm_source=blogxgwz1 https://www.cnblo ...

  6. Python编写Appium测试用例(1)

    有段时间没有使用python编写测试用例了,很长时间以来,感觉appium这个测试工具确实不错,今天又重新拿起来,分享一下自己学习的一些用例,欢迎大家一起交流.学习! 1.登录客户端 #coding= ...

  7. j2ee,jsp,servlet文件下载server端

    1.getOutputStream() has already been called for this response 报错的原因: 使用tomcat容器调用response.getOutputS ...

  8. Oracle10g中阻塞锁查询更简单

    http://blog.itpub.net/195110/viewspace-677572/ http://blog.sina.com.cn/s/blog_636415010100khcl.html

  9. Caused by: java.lang.NoSuchMethodException: &lt;init&gt; [class android.content.Context, interface android

     在写自己定义的view时,有时会报下面错误: Caused by: java.lang.NoSuchMethodException: <init> [class android.co ...

  10. Python 爬虫从入门到进阶之路(五)

    在之前的文章中我们带入了 opener 方法,接下来我们看一下 opener 应用中的 ProxyHandler 处理器(代理设置). 使用代理IP,这是爬虫/反爬虫的第二大招,通常也是最好用的. 很 ...