使用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"com_mccxxiv_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[alen]=0;
}
(*env)->ReleaseByteArrayElements(env,barr,ba,0); //释放空间
return rtn;
}
JNIEXPORT jint JNICALL Java_com_mccxxiv_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_com_mccxxiv_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_com_mccxxiv_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();
}
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[i]);
}
}
}