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);
}
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 ...
随机推荐
- BZOJ3926: [Zjoi2015]诸神眷顾的幻想乡(广义后缀自动机)
Description 幽香是全幻想乡里最受人欢迎的萌妹子,这天,是幽香的2600岁生日,无数幽香的粉丝到了幽香家门前的太阳花田上来为幽香庆祝生日. 粉丝们非常热情,自发组织表演了一系列节目给幽香看. ...
- BZOJ2565: 最长双回文串(Manacher)
Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同).输入长度为n的串S,求S的最长双回文子串T, ...
- 斜率优化dp练习
1.HDU3507 裸题,有助于理解斜率优化的精髓. dp[i]=min(dp[j]+m+(sum[i]-sum[j])2) 很显然不是单调队列. 根据斜率优化的的定义,就是先设两个决策j,k 什么时 ...
- Android RecyclerView And CardView
Google I/O 2014大会公布Android L系统,还有Material Design全新的设计风格.而Material Design卡片式的设计.Google Play应用商店和G+ AP ...
- php设置http请求头信息和响应头信息
php设置http请求头信息和响应头信息 设置请求服务器的头信息可以用fsockopen,curl组件,header函数只能用来设置客户端响应的头信息,不能设置服务器的头信息. 例子; 一.head ...
- node.js服务器核心http和文件读写
使用htpp给客服端的数据,把数据交给浏览器渲染.利用 http创建服务器,如客户端请求为:127.0.0.1:3000或127.0.0.1:3000/xxx.html时 ,判断www文件夹中,文件 ...
- 前端面试题(webpack)
(前端面试题大全,持续更新) webpack3升级到4为什么会提升速度? webpack优化有哪些? webpack的css-loader原理讲一下 webpack压缩js css的方法
- vue使用jsonp
axios不支持jsonp,所以需使用其他插件:vue-jsonp npm i vue-jsonp -S 然后在 src/main.js : import Vue from 'vue' import ...
- mycat快速体验(转)
横空出世的MyCat截至到2015年4月,保守估计已经有超过60个项目在使用,主要应用在电信领域.互联网项目,大部分是交易和管理系统,少量是信息系统.比较大的系统中,数据规模单表单月30亿.本人也初步 ...
- 【Codeforces Round #301 (Div. 2) C】 Ice Cave
[链接] 我是链接,点我呀:) [题意] 给你一个n*m的地图. 每个地图为0的时候可以安全走过,且走过后变成1. (一定要离开之后才会变成1) 而为1的则走过之后会掉入下一层. 你一开始在初始位置( ...