简析JNI的使用
来源:互联网 发布:尚德自考靠谱 知乎 编辑:程序博客网 时间:2024/06/06 00:11
简析JNI的使用
1、创建一个JNI的demo,JNIDemo在main中创建一个jni包,在jni包中创建一个TestJNI.c的C文件,在java中创建一个JNI的类。注意:创建的TestJNI的后缀是.c一定不能搞错。
2、接下来再到build.grald中配置ndk,这里的moduleName可以不配置,没有配置就是默认的包的名字。不过我建议这里配置好,改动了到时候需要改几个地方。
defaultConfig { ... ndk{ moduleName "World" //so文件:lib + moduleName + .so abiFilters "armeabi","armeabi-v7a","x86" //cpu的类型 ldLibs "log" //在C代码中打印日志 }}
3、做完这些我们就可以在JNITest中添加一些方法来测试是否能调用C代码
6、开始C代码的操作了,导入刚刚生成的头文件
public class JNITest { { System.loadLibrary("World"); } /** * 让C代码执行加法运算,返回结果 * @param x * @param y * @return */ public native int add(int x,int y); /** * 传入字符串,C代码进行拼接 * @param str * @return */ public native String sayHello(String str); /** * 让C代码给每个元素都加上10 * @param intArrary * @return */ public native int[] increaseArrayEles(int[] intArrary); /** * 判断字符串是否相同,返回200说明正确,返回400说明错误 * @param str * @return */ public native int stringIsEqual(String str);}
4、接下来点击build >> rebuild project,如下图;
如果不执行此操作不会生成ndk等一系列文件,这时候我们发现生成的so库的名字就是我们配置的名字,如下图:
第一张图是没有rebuild project之前。
5、生成头文件(至于啥是头文件百度哈),选中JNI类名右键copy reference获取全类名 >> java包右键 >> show in Explorer >> 弹出了main包 >> 进入java >> 在此处打开命令窗口 >> javah 全类名 >> 打开工程java报下如果有一个.h的文件就完成了。如下图:
把.h文件拖到jni包中
#include "com_valiantman_javacallc_JNITest.h"
接下来把JNI类中的方法一一在TestJNI中实现,添加一些简单的逻辑。#include "com_valiantman_javacallc_JNITest.h"#include <string.h>char* _JavaStringToCString(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;}jint Java_com_valiantman_javacallc_JNITest_add(JNIEnv *env, jobject jobj, jint ji, jint jy) { int result = ji + jy; return result;}jstring Java_com_valiantman_javacallc_JNITest_sayHello(JNIEnv *env, jobject jobj, jstring str) { char* java = _JavaStringToCString(env,str);//拼接后的结果也在这个字段 char* text = " World"; //拼接函数strcat, 结果放在第一个参数中 strcat(java,text); jstring result = (*env) ->NewStringUTF(env,java); return result;}jintArray Java_com_valiantman_javacallc_JNITest_increaseArrayEles(JNIEnv *env, jobject jobj, jintArray arr) { int size = (*env)->GetArrayLength(env,arr); jint* intArray = (*env)->GetIntArrayElements(env,arr,JNI_FALSE); //遍历数组,给每个元素加上10 int i; for (int i = 0; i < size; ++i) { *(intArray + i) += 10; } return arr;}jint Java_com_valiantman_javacallc_JNITest_checkPassword (JNIEnv *env, jobject jobj, jstring jpswd){ char * password = "123456"; char * jpassword = _JavaStringToCString(env,jpswd); //函数比较字符串是否相同 int code = strcmp(password,jpassword); if(code == 0){ return 200; } else{ return 400; }}
第一个方法是把从java中传入的字符串转换成C代码,其中的逻辑我不太懂。这个我们不用太在意。在C代码中方法的组成是 :返回值类型 Java_全类名_方法名(JNIEnv* env, jobject instance, ...){
...
}
7、最后一步最简单了,在MainActivity中添加几个对应的点击事件就可以了,然后打印Log或者Toast验证是否执行。
@Override public void onClick(View v) { switch (v.getId()){ case R.id.btn1: int result1 = jniTest.add(1, 1); Toast.makeText(this, "result1= " + result1, Toast.LENGTH_SHORT).show(); Log.e(TAG, "onClick: result= " + result1); break; case R.id.btn2: String result2 = jniTest.sayHello("Hello"); Toast.makeText(this, "result2= " + result2, Toast.LENGTH_SHORT).show(); break; case R.id.btn3: int[] arr1 = {1,2,3}; int[] arr = jniTest.increaseArrayEles(arr1); Toast.makeText(this, "result1= " + arr[0] + " / " + arr[1] + " / " + arr[2], Toast.LENGTH_SHORT).show(); break; case R.id.btn4: int code = jniTest.stringIsEqual("123456"); Toast.makeText(this, "code= " + (code==200?"相同":"不相同"), Toast.LENGTH_SHORT).show(); break; } }
到最后才发现没有在C代码中打印log,哈哈.... 打印日志很简单,在C代码中导入打印日志的包就可以了。如下
#include <android/log.h>#define LOG_TAG "JNI"#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, __VA_ARGS__)#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG, __VA_ARGS__)#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG, __VA_ARGS__)
LOGE("value=%d\n ",value);
想打印啥就打印啥吧,哈哈...如果代码不通,有啥问题给我留言。我会尽最大努力给大家解决。谢谢...
1+1运算太难了,我用C代码算出结果了,真心不简单。如果ndk没有配置好可以到我前面的博客看下怎么配置。
阅读全文
2 0
- 简析JNI的使用
- JNI的使用(ZT)
- JNI 的使用
- JNI的使用
- 使用j2se的jni
- JNI 的使用
- JNI的简单使用
- JNI的使用
- JNi 的使用
- JNI的使用
- JNI的使用
- jni的学习使用
- jni的使用
- Android JNI的使用
- JNI的使用
- JNI的使用
- jni的使用
- jni的简单使用
- mybatis传多个参数(三种方法)详细
- Cardboard的学习(三)目录介绍
- 将自定义标签打包为jar包并提供给JSP使用
- 学习笔记:数据结构、算法::求最大子列和
- ES6 notes
- 简析JNI的使用
- PostgreSQL 百万级每秒的流式实时统计应用
- Luogu 1111 修复公路
- LeetCode: 566. Reshape the Matrix
- Char 和 Varchar 的区别
- Entity Framework Code First实体对象变动跟踪
- Android 启动退出时的相关问题
- Android_WebView踩坑系列
- 关于前端兼容所有浏览器的一些想法和总结