NDK开发—基础知识实战Demo
2016-08-29 10:09
302 查看
简介
前面写了几篇NDK相关的文章:NDK开发-简介&环境搭建(Eclipse,Android Studio)
NDK开发-Android Studio+gradle-experimental开发NDK,
NDK开发-零散知识点整理
这个demo就是对这几篇文章中涉及内容的一个应用。其功能只是对数组进行排序。如果单纯使用Java来做十分简单,只需写个排序方法,或者将数组转化为集合,然后调用sort函数就ok了。
但我们的目的是练习JNI所以需要使劲的折腾一下,其中主要涉及了:
Java调用JNI函数
JNI调用Java函数
JNI中打印Android Log
JNI中调用c++函数库
JNI调用普通方法/静态方法
JNI全局变量使用
JNI数组的操作
JNI异常处理
演示图
点击按钮对数组排序:
排序成功:
Java代码:
Activity代码:
public class MainActivity extends AppCompatActivity { // 导入动态库 static { System.loadLibrary("test"); } // 本地排序方法 public native boolean doSort(int [] array); private Button mOrderBtn; private TextView mResultText; // 需要排序的数组 int[] orderArrays = {6,2,5,9,1,3,4,7,8,0,10}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 调用jni调用静态方法返回一个字符串(hello world?) Log.d("TestNDK", JNIHelper.getStringFromNative()); mResultText = (TextView) this.findViewById(R.id.result); setResultText(orderArrays); mOrderBtn = (Button) this.findViewById(R.id.plus_btn); mOrderBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 调用本地排序方法, 根据是否有异常打印success/failed boolean isSuccess = doSort(orderArrays); mOrderBtn.setText(isSuccess?"success":"failed"); } }); } public void setResultText(String resultText) { mResultText.setText(resultText); } public void setResultText(int[] array) { mResultText.setText(Arrays.toString(array)); } }
JNI工具类:
public class JNIHelper { @Keep private void updateStatus(String msg) { if (msg.toLowerCase().contains("error")) { Log.e("JniHandler", "Native Err: " + msg); } else { Log.i("JniHandler", "Native Msg: " + msg); } } public static native String getStringFromNative(); }
JNI代码
头文件
#include <jni.h> /* Header for class com_dean_testndk_JNIHelper */ #ifndef _Included_com_dean_testndk_JNIHelper #define _Included_com_dean_testndk_JNIHelper #ifdef __cplusplus extern "C" { #endif /* * Class: com_dean_testndk_JNIHelper * Method: getStringFromNative * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_dean_testndk_JNIHelper_getStringFromNative(JNIEnv *, jclass); JNIEXPORT jboolean JNICALL Java_com_dean_testndk_MainActivity_doSort(JNIEnv *, jobject, jintArray); #ifdef __cplusplus } #endif #endif
c++代码
// // Created by Dean Guo on 7/23/16. // #include "com_dean_testndk_JNIHelper.h" #include "string.h" #include "iostream" #include "vector" #include "algorithm" #include <android/log.h> using namespace std; // Android log function wrappers static const char* kTAG = "testNDK"; #define LOGI(...) \ ((void)__android_log_print(ANDROID_LOG_INFO, kTAG, __VA_ARGS__)) #define LOGW(...) \ ((void)__android_log_print(ANDROID_LOG_WARN, kTAG, __VA_ARGS__)) #define LOGE(...) \ ((void)__android_log_print(ANDROID_LOG_ERROR, kTAG, __VA_ARGS__)) struct GLOBAL_CONTEXT { JavaVM* javaVM; jclass mainActivityClz; jobject mainActivityObj; jclass jniHelperClz; jobject jniHelperObj; }; /** * 全局引用 */ GLOBAL_CONTEXT mContext; void sendJavaMsg(JNIEnv *env, jobject instance, jmethodID func, const char *msg) { jstring javaMsg = env->NewStringUTF(msg); env->CallVoidMethod(instance, func, javaMsg); } void callSetResult(JNIEnv *env, vector<int> vector_) { char buff[1000] = ""; vector<int>::iterator it; for (it = vector_.begin(); it != vector_.end(); it++) { char numChar[100] = ""; sprintf(numChar, "%d", *it); strcat(numChar, ","); strcat(buff, numChar); } jstring javaMsg = env->NewStringUTF(buff); jthrowable ex = env->ExceptionOccurred(); if (0 != ex) { env->ExceptionClear(); env->DeleteLocalRef(javaMsg); LOGE("Exception-sendJavaMsg!"); } else { jmethodID methodID = env->GetMethodID(mContext.mainActivityClz, "setResultText", "(Ljava/lang/String;)V"); env->CallVoidMethod(mContext.mainActivityObj, methodID, javaMsg); env->DeleteLocalRef(javaMsg); } } /** * 根据排序好的vector集合, 创建排序数组返回 */ void callSetArrayResult(JNIEnv *env, vector<int> vector_) { int size = vector_.size(); // 排序后需要返回的数组 jintArray array = env->NewIntArray(size); // 为jni数组赋值 jint *num = new jint[size]; for (int i = 0; i < size; i++) { num[i] = vector_[i]; } env->SetIntArrayRegion(array, 0, size, num); // 调用java方法传递排序好的数组 jmethodID methodID = env->GetMethodID(mContext.mainActivityClz, "setResultText", "([I)V"); env->CallVoidMethod(mContext.mainActivityObj, methodID, array); // 释放数组 env->ReleaseIntArrayElements(array, num, 0); } /** * 系统函数, JNI初始化时调用。 * 可在这个函数这里做一些初始化赋值 */ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { LOGI("JNI_OnLoad"); JNIEnv* env; mContext.javaVM = vm; if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) { LOGE("JNI_ERR"); return JNI_ERR; // 不支持该版本 } // 对JNIHelper设置全局引用 jclass clz = env->FindClass("com/dean/testndk/JNIHelper"); mContext.jniHelperClz = (jclass) env->NewGlobalRef(clz); jmethodID jniHelperCtor = env->GetMethodID(mContext.jniHelperClz, "<init>", "()V"); jobject handler = env->NewObject(mContext.jniHelperClz, jniHelperCtor); mContext.jniHelperObj = env->NewGlobalRef(handler); // 调用JNIHelper中updateStatus方法打印信息 jmethodID statusId = env->GetMethodID(mContext.jniHelperClz, "updateStatus", "(Ljava/lang/String;)V"); sendJavaMsg(env, mContext.jniHelperObj, statusId, "JNI: initializing..."); return JNI_VERSION_1_6; } /** * 简单返回一个字符串 */ JNIEXPORT jstring JNICALL Java_com_dean_testndk_JNIHelper_getStringFromNative (JNIEnv *env, jclass jclz) { return env->NewStringUTF("from Native"); } /** * 排序方法, 成功返回true, 否则false */ JNIEXPORT jboolean JNICALL Java_com_dean_testndk_MainActivity_doSort(JNIEnv *env, jobject instance, jintArray arr_) { // 设置全局引用 mContext.mainActivityClz = env->GetObjectClass(instance); mContext.mainActivityObj = env->NewGlobalRef(instance); // 获取传递过来的数组指针 jint *nums = env->GetIntArrayElements(arr_, NULL); // 获取数组长度 jsize len = env->GetArrayLength(arr_); // 使用标准库中的vector排序 vector<int> mVector; for (int i=0; i< len; i++) { mVector.push_back(nums[i]); } sort(mVector.begin(), mVector.end()); // 调用返回结果函数 callSetArrayResult(env, mVector); // 释放数组 env->ReleaseIntArrayElements(arr_, nums, 0); // 判断是否有异常, 没有表示成功返回true, 否则false jthrowable ex = env->ExceptionOccurred(); if (0 != ex) { env->ExceptionClear(); LOGE("Exception!"); return false; } else { return true; } }
最后
下载
https://github.com/a396901990/TestNDK总结
demo中所有详细的知识点都可以在NDK开发-零散知识点整理中找到。如果想深入NDK推荐Google NDK的官方demo:
https://github.com/googlesamples/android-ndk
相关文章推荐
- NDK开发—基础知识实战Demo
- NDK开发—基础知识实战Demo
- 《Spring 3.x 企业应用开发实战》学习笔记 第三章 IoC容器概述 3.2 相关Java基础知识 类装载器 反射机制
- Android NDK开发之JNI基础知识
- Android音频开发(1):基础知识和demo
- 第一篇:微信公众平台开发实战Java版之了解微信公众平台基础知识以及资料准备
- Java WEB开发实战 之 第二部分:Web应用基础知识【私塾在线原创】
- 《精通Spring4.X企业应用开发实战》读后感第七章(AOP基础知识、jdk动态代理,CGLib动态代理)
- 第一篇:微信公众平台开发实战Java版之了解微信公众平台基础知识以及资料准备
- Java WEB开发实战 之 第一部分:复习必备的基础知识【私塾在线原创】
- 第一篇:微信公众平台开发实战Java版之了解微信公众平台基础知识以及资料准备
- 《Spring 3.x 企业应用开发实战》学习笔记 第三章 IoC容器概述 3.2 相关Java基础知识 类装载器 反射机制
- 通过demo学习OpenStack开发所需的基础知识 -- 数据库(1)
- Web项目开发常用基础知识集锦
- 每一个软件开发人员绝对必须掌握的关于 Unicode 和字符集的最基础的知识
- AT91AM9200 USB HOST开发(二)—— USB基础知识介绍
- EBS开发基础知识
- 关于手机开发的一些比较基础的知识
- 移动项目开发笔记(C#泛型编程基础知识总结)
- EBS开发基础知识