设为首页 加入收藏

TOP

Java中JNI的使用(下)(二)
2018-10-08 10:03:58 】 浏览:396
Tags:Java JNI 使用
//native methods registered by JNI_OnLoad static jint native_newInstance (JNIEnv *env, jclass); //实现native方法 /* * Class: com_young_soundtouch_SoundTouch * Method: native_newInstance * Signature: ()I */ static jint native_newInstance (JNIEnv *env, jclass ) { int instanceID = ++sInstanceIdentifer; SoundTouchWrapper *instance = new SoundTouchWrapper(); if (instance != NULL) { sInstancePool[instanceID] = instance; ++sInstanceCount; } LOGDBG("create new SouncTouch instance:%d", instanceID); return instanceID; } //构造JNINativeMethod数组 static JNINativeMethod gsNativeMethods[] = { { "native_newInstance", "()I", reinterpret_cast<void *> (native_newInstance) } }; //计算数组大小 static const int gsMethodCount = sizeof(gsNativeMethods) / sizeof(JNINativeMethod); //JNI_OnLoad,注册native方法。 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv* env; jclass clazz; LOGD("JNI_OnLoad called"); if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { return -1; } //FULL_CLASS_NAME是个宏定义,定义了对应java类的全名(要把包名中的点(.)_替换成斜杠(/)) clazz = env->FindClass(FULL_CLASS_NAME); LOGDBG("register method, method count:%d", gsMethodCount); //注册JNI函数 env->RegisterNatives(clazz, gsNativeMethods, gsMethodCount); //必须返回一个JNI_VERSION_1_1以上(不含)的版本号,否则直接加载失败 return JNI_VERSION_1_6; }

实战技巧篇

这里主要是巧用 C 中的宏来减少重复工作:

迅速生成全名

//修改包名时只需要改以下的宏定义即可
#define FULL_CLASS_NAME "com/young/soundtouch/SoundTouch"
#define func(name) Java_ ## com_young_soundtouch_SoundTouch_ ## name
#define constance(cons) com_young_soundtouch_SoundTouch_ ## cons

比如func(native_1newInstance)展开成:Java_com_young_soundtouch_SoundTouch_native_1newInstance即JNI中需要导出的函数名(不过用动态注册方式没太大用了)

constance(AUDIO_FORMAT_PCM16)展开成com_young_soundtouch_SoundTouch_AUDIO_FORMAT_PCM16这个着实有用。

而且如果包名改了也可以很方便的适应之。

安卓的log

//define __USE_ANDROID_LOG__ in makefile to enable android log
#if defined(__ANDROID__) && defined(__USE_ANDROID_LOG__)
#include <android/log.h>
#define LOGV(...)   __android_log_print((int)ANDROID_LOG_VERBOSE, "ST_jni", __VA_ARGS__)
#define LOGD(msg)  __android_log_print((int)ANDROID_LOG_DEBUG, "ST_jni_dbg", "line:%3d %s", __LINE__, msg)
#define LOGDBG(fmt, ...) __android_log_print((int)ANDROID_LOG_DEBUG, "ST_jni_dbg", "line:%3d " fmt, __LINE__, __VA_ARGS__)
#else
#define LOGV(...) 
#define LOGD(fmt) 
#define LOGDBG(fmt, ...) 
#endif

通过这样的宏定义在打 LOGD 或者 LOGDBG 的时候还能自动加上行号!调试起来爽多了!

C++中清理内存的方式

由于 C++ 里面需要手动清除内存,因此我的解决方案是定义一个 map,给每个实例一个 id,用 id 把 Java 中的对象和 native 中的对象绑定起来。在 Java 层定义一个 release 方法,用来释放本地的对象。 本地的 KEY-对象 映射 static std::map<int, SoundTouchWrapper*> sInstancePool;

关于NDK

因为安卓的约定是把本地代码放到 jni 目录下面,但是假如有多个 jni lib 的时候会比较混乱,所以方案是每一个 lib 都在 jni 里面建一个子目录,然后 jni 里面的 Android.mk 就可以去构建子目录中的 lib 了。

jni/Android.mk 如下(超级简单):

LOCAL_PATH := $(call my-dir)
include $(call all-subdir-makefiles)

然后在子目录 soundtouch_module 中的 Android.mk 就可以像一般的 Android.mk 一样书写规则了。

同时记录一下在 Andoroid.mk 中使用 makefile 内建函数 wildcard 的方法。 有时候源文件是一个目录

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇ERROR 1044 (42000) : Access den.. 下一篇Disruptor源码阅读笔记

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目