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 ...
 
随机推荐
- FileUpload1上传控件
			
<asp:FileUpload ID="FileUpload1" runat="server" /> string fn = System.IO.P ...
 - 阿里2014校招笔试题(南大)——利用thread和sleep生成字符串的伪随机序列
			
引言:题目具体描述记不大清了,大概是:Linux平台,利用线程调度的随机性和sleep的不准确性,生成一个各位均不相同的字符数组的伪随机序列.不得使用任何库函数.(这句记得清楚,当时在想线程库算不算, ...
 - SAP  SMARTFORMS-基于内存方式在report程序中传递数据到smartforms显示
			
一.准备工作 1.新建include程序 1> include程序名字:ZDD_INC_0104 2> ZDD_INC_0104 程序中的内容为 2.使用T-CODE :SE11新建两个 ...
 - 51 NOD 1384 全排列(STL    搜索)
			
1384 全排列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出一个字符串S(可能又重复的字符),按照字典序 ...
 - 【leetcode】Best Time to Buy and Sell  2(too easy)
			
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
 - 【vs2010调试】当前不会命中断点 源代码与原始版本不同
			
解决方案:全选CPP文件内容,选择 “编辑”-“高级”-“设置选定内容的格式”,保存,重新编译.
 - osgconv 将多个模型合成一个模型
			
osgconv a.osg b.osg c.osg BigOne.ive 以上命令的作用是将a.osg.b.osg.c.osg三个模型合并到BigOne.ive模型
 - ios电话/密码/验证码/身份证的正则表达式
			
// 一 .电话号码正则表达式 -(BOOL)testPhoneNumber:(NSString *)text { NSString *regex =@"(13[0-9]|0[1-9]|0[ ...
 - 开启后台 Service 闪退
			
04-29 15:36:23.395: E/ActivityThread(15275): Performing stop of activity that is not resumed: {com.e ...
 - 4.3 map和multimap
			
使用map multimap必须包含头文件map *:multimap 1)multimap定义 template<class Key,class Pred=less<Key>,cl ...