博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于 Android NDK 的学习之旅----- C调用Java
阅读量:5748 次
发布时间:2019-06-18

本文共 6292 字,大约阅读时间需要 20 分钟。

hot3.png

许多成熟的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、  层调用 Java 方法

 

2、设计实现

1、界面设计如下:

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

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

 

 

2、      关键代码说明

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

 

详细 映射方法  调用方法 请参考  ,这个很重要 

 

3、      Java 上层 关键代码

TestProvider.Java 的两个方法

 

package com.duicky;
 
/**
 *
 *
 * 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)

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

 

 

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 传递的参数,和 吐司出相对应的信息

 

 

4C调用Java注意点

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

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

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

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

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

 

 

 

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

 

点击下载源码 

本文出自  博客 , 转载请注明出处 

转载于:https://my.oschina.net/zhuzihasablog/blog/115095

你可能感兴趣的文章
Java笔记-反射机制(一)
查看>>
OpenCV在Android中的集成与简单使用
查看>>
redux v3.7.2源码解读与学习之 applyMiddleware
查看>>
【React】为什么我不再使用setState?
查看>>
Git原理与高级使用(3)
查看>>
从JDK源码看Writer
查看>>
Express 结合 Webpack 实现HMRwi
查看>>
listen源码分析第一篇 address:port分析
查看>>
SQL模糊查询通配符_和%处理
查看>>
ssl免费申请
查看>>
我的友情链接
查看>>
mysql优化的相关知识
查看>>
基于protobuf的RPC实现
查看>>
ehcache 常用参数
查看>>
坚信每个人都能成为品牌
查看>>
Java语言的基础知识3
查看>>
JAVA的对象复制
查看>>
jquery要怎么写才能速度最快?(转)
查看>>
cisco设备IOS上传、备份、设置启动IOS
查看>>
打开Office报错
查看>>