sctarena 发表于 2012-11-26 15:24

使用JNI在java中调用C代码

使用JNI在java中调用C代码
1.定义个类来定义java的native方法
public class DataProvider {
public native int add(int x ,int y);
public native String sayHelloInC(String s);
public native int[] intMethod(int[] iNum);
}
2.用javah编译那个native的类.
3.新建jni的文件夹.把刚刚编译生成的.h的头文件给拷贝进来.
4.在jni的文件夹下新建XX.c文件
5.编写c代码
#include<stdio.h>
#include"cn_itcast_ndk3_DataProvider.h"
#include <android/log.h>
#include<jni.h>
#include<malloc.h>
#define LOG_TAG "System.out"
#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中的string 转化成 c语言中 char数组
//返回值是 char数组的首地址
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);         //"\0"
memcpy(rtn,ba,alen);
rtn=0;
}
(*env)->ReleaseByteArrayElements(env,barr,ba,0);//释放空间
return rtn;
}//www.m6wang.com


JNIEXPORT jint JNICALL Java_cn_itcast_ndk3_DataProvider_add
(JNIEnv * env, jobject obj, jint x, jint y){
LOGI("x= %d",x);
LOGI("y= %d",y);
return x+y;
}


JNIEXPORT jstring JNICALL Java_cn_itcast_ndk3_DataProvider_sayHelloInC
(JNIEnv * env, jobject obj, jstring jstr){
char* p = Jstring2CStr(env,jstr); // 返回的是char数组的首地址
// 在c语言中 打印 java传递过来的字符串
LOGI("in c code = %s",p);

char* newstr="nihao ";

   //strcat string cat(dest,source);strcat(newstr,p);
// 要求目标的 内存空间 可以存放 拼装后的字符串的大小
   //strcat(newstr,p) 该函数是把两个字符串连接起来
   return (*env)->NewStringUTF(env,strcat(p,newstr)); //该函数是把c的字符串转换成jstring
}


JNIEXPORT jintArray JNICALL Java_cn_itcast_ndk3_DataProvider_intMethod
(JNIEnv * env, jobject obj, jintArray jintarr){
int len = (*env)->GetArrayLength(env,jintarr);//获取java数组的长度
LOGI("len = %d",len);
LOGI("dizhi = %#x",&jintarr);
jint* arr = (*env)->GetIntArrayElements(env,jintarr,0);//获取数组中的每个元素.0是指不使用拷贝.1是指使用拷贝.达内就业
int i =0;
int temp;
for(;i<len;i++){
LOGI("arr[%d] = %d",i, *(arr+i));
//*(arr+i) +=10;
temp = *(arr+i) + 10;//修改数组中的值
(*env)->SetIntArrayRegion(env,jintarr,i,1,&temp);//操作数组里面的元素

}
(*env)->ReleaseIntArrayElements(env,jintarr,arr,0); //释放内存空间
return jintarr;
}
6.在jni文件夹下新建Android.mk文件
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS) #类似于工具初始化的操作

LOCAL_MODULE    := Hello
LOCAL_SRC_FILES := Hello.c

LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)
7.用ndk-build命令编译
8.在主Activity中调用native方法
public class MainActivity extends Activity {
//静态代码块是加载编译生成的c的动态库文件
static{
System.loadLibrary("Hello");
}

    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
    }
   
   
    public void passInt(View view){
   DataProvider provider = new DataProvider();
   int result = provider.add(3, 5);
   Toast.makeText(this, "相加的结果是: "+ result, 1).show();
    }//www.sctarena.com
   
    public void passsString(View view){
   DataProvider provider = new DataProvider();
   String result = provider.sayHelloInC("zhang san");
   Toast.makeText(this,result, 1).show();
    }
   
    public void passsIntArr(View view){
   int[] arr ={1,2,3,4,5};
   System.out.println(arr.toString());
   DataProvider provider = new DataProvider();
   int[] result =provider.intMethod(arr);
   
   for(int i =0;i<result.length;i++){
   System.out.println("java result["+i+"]=" +result);
   }
    }
}
页: [1]
查看完整版本: 使用JNI在java中调用C代码