Android使用JNI实现Java与C之间传递数据(转)
介绍Java如何将数据传递给C和C回调Java的方法。 java传递数据给C,在C代码中进行处理数据,处理完数据后返回给java。C的回调是Java传递数据给C,C需要用到Java中的某个方法,就需要调用java的方法。
Android中使用JNI七个步骤:
1.创建一个android工程
2.JAVA代码中写声明native 方法 public native String helloFromJNI();
3.用javah工具生成头文件
4. 创建jni目录,引入头文件,根据头文件实现c代码
5.编写Android.mk文件
6.Ndk编译生成动态库
7.Java代码load 动态库.调用native代码
Java调用C进行数据传递
这里分别传递整形、字符串、数组在C中进行处理。
声明native 方法:
- public class DataProvider {
- // 两个java中的int 传递c 语言 , c语言处理这个相加的逻辑,把相加的结果返回给java
- public native int add(int x ,int y);
- //把一个java中的字符串传递给c语言, c 语言处理下字符串, 处理完毕返回给java
- public native String sayHelloInC(String s);
- //把一个java中int类型的数组传递给c语言, c语言里面把数组的每一个元素的值 都增加5,
- //然后在把处理完毕的数组,返回给java
- public native int[] intMethod(int[] iNum);
- }
以上方法要在C中实现的头文件,头文件可以理解为要在C中实现的方法
其中 JENEnv* 代表的是java环境 , 通过这个环境可以调用java的方法,jobject 表示哪个对象调用了 这个c语言的方法, thiz就表示的是当前的对象
- /* DO NOT EDIT THIS FILE - it is machine generated */
- #include <jni.h>
- /* Header for class cn_itcast_ndk3_DataProvider */
- #ifndef _Included_cn_itcast_ndk3_DataProvider
- #define _Included_cn_itcast_ndk3_DataProvider
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Class: cn_itcast_ndk3_DataProvider
- * Method: add
- * Signature: (II)I
- */
- JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add
- (JNIEnv *, jobject, jint, jint);
- /*
- * Class: cn_itcast_ndk3_DataProvider
- * Method: sayHelloInC
- * Signature: (Ljava/lang/String;)Ljava/lang/String;
- */
- JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC
- (JNIEnv *, jobject, jstring);
- /*
- * Class: cn_itcast_ndk3_DataProvider
- * Method: intMethod
- * Signature: ([I)[I
- */
- JNIEXPORT jintArray JNICALL Java_cn_itcast_ndk3_DataProvider_intMethod
- (JNIEnv *, jobject, jintArray);
- #ifdef __cplusplus
- }
- #endif
- #endif
C代码出了要引用头文件外,还要引入日志信息,以方便在C 中进行调试
- //引入头文件
- #include "cn_itcast_ndk3_DataProvider.h"
- #include <string.h>
- //导入日志头文件
- #include <android/log.h>
- //修改日志tag中的值
- #define LOG_TAG "logfromc"
- //日志显示的等级
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
- // java中的jstring, 转化为c的一个字符数组
- char* Jstring2CStr(JNIEnv* env, jstring jstr)
- {
- char* rtn = NULL;
- jclass clsstring = (*env)->FindClass(env,"java/lang/String");
- jstring strencode = (*env)->NewStringUTF(env,"GB2312");
- jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
- jbyteArray barr= (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");
- jsize alen = (*env)->GetArrayLength(env,barr);
- jbyte* ba = (*env)->GetByteArrayElements(env,barr,JNI_FALSE);
- if(alen > 0)
- {
- rtn = (char*)malloc(alen+1); //new char[alen+1]; "\0"
- memcpy(rtn,ba,alen);
- rtn[alen]=0;
- }
- (*env)->ReleaseByteArrayElements(env,barr,ba,0); //释放内存
- return rtn;
- }
- //处理整形相加
- JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add
- (JNIEnv * env, jobject obj, jint x, jint y){
- //打印 java 传递过来的 jstring ;
- LOGI("log from c code ");
- LOGI("x= %ld",x);
- LOGD("y= %ld",y);
- return x+y;
- }
- //处理字符串追加
- JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC
- (JNIEnv * env, jobject obj, jstring str){
- char* p = Jstring2CStr(env,str);
- LOGI("%s",p);
- char* newstr = "append string";
- //strcat(dest, sorce) 把sorce字符串添加到dest字符串的后面
- LOGI("END");
- return (*env)->NewStringUTF(env, strcat(p,newstr));
- }
- //处理数组中的每一个元素
- JNIEXPORT jintArray JNICALL Java_cn_itcast_ndk3_DataProvider_intMethod
- (JNIEnv * env, jobject obj, jintArray arr){
- // 1.获取到 arr的大小
- int len = (*env)->GetArrayLength(env, arr);
- LOGI("len=%d", len);
- if(len==0){
- return arr;
- }
- //取出数组中第一个元素的内存地址
- jint* p = (*env)-> GetIntArrayElements(env,arr,0);
- int i=0;
- for(;i<len;i++){
- LOGI("len=%ld", *(p+i));//取出的每个元素
- *(p+i) += 5; //取出的每个元素加五
- }
- return arr;
- }
编写Android.mk文件
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE := Hello
- LOCAL_SRC_FILES := Hello.c
- #增加 log 函数对应的log 库 liblog.so libthread_db.a
- LOCAL_LDLIBS += -llog
- include $(BUILD_SHARED_LIBRARY)
Java代码load 动态库.调用native代码
- static{
- System.loadLibrary("Hello");
- }
- DataProvider dp;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- dp = new DataProvider();
- }
- //add对应的事件
- public void add(View view){
- //执行C语言处理数据
- int result = dp.add(3, 5);
- Toast.makeText(this, "相加的结果"+ result, 1).show();
- }
C中回调java方法
声明native 方法:
- public class DataProvider{
- public native void callCcode();
- public native void callCcode1();
- public native void callCcode2();
- ///C调用java中的空方法
- public void helloFromJava(){
- System.out.println("hello from java ");
- }
- //C调用java中的带两个int参数的方法
- public int Add(int x,int y){
- System.out.println("相加的结果为"+ (x+y));
- return x+y;
- }
- //C调用java中参数为string的方法
- public void printString(String s){
- System.out.println("in java code "+ s);
- }
- }
头文件可以用jdk自带的javah进行自动生成,使用javap -s可以获取到方法的签名。
C代码实现回调需要三个步骤:首先要要获取到 某个对象 , 然后获取对象里面的方法 ,最后 调用这个方法 .
- #include "cn_itcast_ndk4_DataProvider.h"
- #include <string.h>
- #include <android/log.h>
- #define LOG_TAG "logfromc"
- #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
- //1.调用java中的无参helloFromJava方法
- JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode
- (JNIEnv * env , jobject obj){
- // 获取到DataProvider对象
- char* classname = "cn/itcast/ndk4/DataProvider";
- jclass dpclazz = (*env)->FindClass(env,classname);
- if (dpclazz == 0) {
- LOGI("not find class!");
- } else
- LOGI("find class");
- //第三个参数 和第四个参数 是方法的签名,第三个参数是方法名 , 第四个参数是根据返回值和参数生成的
- //获取到DataProvider要调用的方法
- jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"helloFromJava","()V");
- if (methodID == 0) {
- LOGI("not find method!");
- } else
- LOGI("find method");
- //调用这个方法
- (*env)->CallVoidMethod(env, obj,methodID);
- }
- // 2.调用java中的printString方法传递一个字符串
- JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode1
- (JNIEnv * env, jobject obj){
- LOGI("in code");
- // 获取到DataProvider对象
- char* classname = "cn/itcast/ndk4/DataProvider";
- jclass dpclazz = (*env)->FindClass(env,classname);
- if (dpclazz == 0) {
- LOGI("not find class!");
- } else
- LOGI("find class");
- // 获取到要调用的method
- jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"printString","(Ljava/lang/String;)V");
- if (methodID == 0) {
- LOGI("not find method!");
- } else
- LOGI("find method");
- //调用这个方法
- (*env)->CallVoidMethod(env, obj,methodID,(*env)->NewStringUTF(env,"haha"));
- }
- // 3. 调用java中的add方法 , 传递两个参数 jint x,y
- JNIEXPORT void JNICALL Java_cn_itcast_ndk4_DataProvider_callCcode2
- (JNIEnv * env, jobject obj){
- char* classname = "cn/itcast/ndk4/DataProvider";
- jclass dpclazz = (*env)->FindClass(env,classname);
- jmethodID methodID = (*env)->GetMethodID(env,dpclazz,"Add","(II)I");
- (*env)->CallIntMethod(env, obj,methodID,3l,4l);
- }
转自:http://blog.csdn.net/furongkang/article/details/6857610
Android使用JNI实现Java与C之间传递数据(转)的更多相关文章
- Android使用JNI实现Java与C之间传递数据
介绍Java如何将数据传递给C和C回调Java的方法. java传递数据给C,在C代码中进行处理数据,处理完数据后返回给java.C的回调是Java传递数据给C,C需要用到Java中的某个方法,就需要 ...
- 【Android基础】利用Intent在Activity之间传递数据
前言: 上一篇文章给大家聊了Intent的用法,如何用Intent启动Activity和隐式Intent,这一篇文章给大家聊聊如何利用Intent在Activity之间进行沟通. 从一个Activ ...
- 【Android 复习】 : Activity之间传递数据的几种方式
在Android开发中,我们通常需要在不同的Activity之间传递数据,下面我们就来总结一下在Activity之间数据传递的几种方式. 1. 使用Intent来传递数据 Intent表示意图,很多时 ...
- Android 笔记-Fragment 与 Activity之间传递数据
Fragment 与 Activity之间传递数据有两种方法.一种是使用setArgument,一种是使用接口回调.以下先学习第一种方法. (1)使用setArgument方法: 为了便于理解,我在这 ...
- Android之间传递数据包
在Android中 ,我们知道,两个activity之间通讯要用到Intent类,传递简单数据的方式我们也已经知道了.那么,如何在两个activity之间传递数据包呢,这就要用到我们的Bundle类了 ...
- Android基础知识04—Activity活动之间传递数据
------活动之间传递数据------ 向下一个活动传递数据: Intent中提供了一系列的putExtra()方法,可以把数据暂存到Intent中,启动另一个活动的时候就可以取出来. 代码: (存 ...
- Activity之间传递数据或数据包Bundle,传递对象,对象序列化,对象实现Parcelable接口
package com.gaojinhua.android.activitymsg; import android.content.Intent; import android.os.Bundle; ...
- 在activity之间传递数据
在activity之间传递数据 一.简介 二.通过intent传递数据 1.在需要传数据的界面调用 intent.putExtra("data1", "我是fry&quo ...
- 28、activity之间传递数据&批量传递数据
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android ...
随机推荐
- [20160731]read a file and print it on the screen
//read a file and print it on the screen import java.io.*; public class MyPrintStreamTest2{ public s ...
- 【Unity3D】计算二维向量夹角(-180到180)
在Unity3D中,有时候我们需要计算二维向量的夹角.二维向量夹角一般在0~180度之前,可以直接调用Vector2.Angle(Vector2 from, Vector2 to)来计算. 但是在有些 ...
- Qt 信号槽如何传递参数(或带参数的信号槽)
信号槽如何传递参数(或带参数的信号槽) 利用Qt进行程序开发时,有时需要信号槽来完成参数传递.带参数的信号槽在使用时,有几点需要注意的地 ...
- cf555b
题意:按顺序给出多个互不相交的区间(表示一些小岛),和一些可以连接区间的桥,每个桥有固定的长度.区间和桥的数量都是2*10^5. 两个相邻的小岛之间的桥的长度必须小于等于最远点距离,大于等于最近点距离 ...
- Effective C++ -----条款26:尽可能延后变量定义式的出现时间
尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率.
- CCF 节日
问题描述 有一类节日的日期并不是固定的,而是以"a月的第b个星期c"的形式定下来的,比如说母亲节就定为每年的五月的第二个星期日. 现在,给你a,b,c和y1, y2(1850 ≤ ...
- VS2013调试时,IIS Express Worker Process 已停止工作
之前调试都没有报错的,今天突然报错了,然后网上找了下资料,很快解决了问题 这是我报错的提示 解决办法: 用管理员身份运行CMD,输入netsh winsock reset并回车(注意,必须是已管理员身 ...
- October 3rd 2016 Week 41st Monday
Better to light one candle than to curse the darkness. 与其诅咒黑暗,不如燃起蜡烛. Sitting in the darkness and wa ...
- Linear regression with multiple variables(多特征的线型回归)算法实例_梯度下降解法(Gradient DesentMulti)以及正规方程解法(Normal Equation)
,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, ,, , ...
- Java返回距离当前时间段
/** * 计算该时间离当前时间的差距 * @param time 格式为:yyyy-MM-dd HH:mm:ss * @return */ public static String getShort ...