您的位置:首页 > 编程语言 > C语言/C++

使用C++实现JNI接口需要注意的事项

2014-04-25 23:14 2011 查看

ECharts5.0版本即将上线,来说说我与ECharts的那些事吧!>>>

 

Android NDK带的jni例子都是使用C定义JNI接口,但是在项目中,因为Native代码是用C++编写的,所以我就使用C++定义JNI接口。没有想到,问题来了,现将问题总结如下:

1、JNIEnv *env参数的使用

所有JNI接口的第一个参数是JNIEnv *env, 在C中,使用方法是

(*env)->NewStringUTF(env, "Hello from JNI!");

但在C++中,其调用方法是

env->NewStringUTF("Hello from JNI!");

为什么有这种区别呢,看看jni.h中关于J 1000 NIEnv的定义就可以知道了:

#if defined(__cplusplus)

typedef _JNIEnv JNIEnv;

#else

typedef const struct JNINativeInterface* JNIEnv;

#endif

可以看到,对于C和C++,定义有所不同,主要原因是C不支持类,所以采用了一种变通的方法。

2、接口找不到

在Java中调用JNI接口时,出现异常,察看日志,发现有如下错误:

WARN/dalvikvm(422): No implementation found for native Lcom/whty/wcity/HelixPlayer;.setDllPath (Ljava/lang/String;)V

检查了几遍代码,Cpp中确实定义了这个接口,而且仔细对照了Java的包名、类名,确实没有错误,那为什么会出现这种问题呢。后来突然想到,JNI接口都是以C的方式定义的,现在使用C++实现,函数定义前是否需要加上extern "C"呢?为此定义了一个头文件,在CPP文件中include该头文件,头文件加上如下代码片断:

#ifdef __cplusplus

extern "C" {

#endif

#endif

...

#ifdef __cplusplus

}

再次尝试,调用成功!

3. 因业务需求,在JNI C++代码中需要用到多线程,同时加入了互斥锁等机制,编译时出现如下问题:

/home/chenzhengyong/android/source/eclair/frameworks/base/include/utils/threads.h:214: undefined reference to `android::Mutex::lock()'

察看了一下ndk中的STABLE-APIS.TXT文档,上面有这样一句:

Note that the Android C library includes support for pthread (<pthread.h>),

so "LOCAL_LIBS := -lpthread" is not needed. The same is true for real-time

extensions (-lrt on typical Linux distributions).

也就是说使用多线程,并不需要增加-lpthread编译选项,看来解决问题还需要从源代码入手。察看frameworks/base/include/utils/threads.h文件,关于Mutex有如下代码片断:

#if defined(HAVE_PTHREADS)
inline Mutex::Mutex() {
pthread_mutex_init(&mMutex, NULL);
}
inline Mutex::Mutex(const char* name) {
pthread_mutex_init(&mMutex, NULL);
}
inline Mutex::Mutex(int type, const char* name) {
if (type == SHARED) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&mMutex, &attr);
pthread_mutexattr_destroy(&attr);
} else {
pthread_mutex_init(&mMutex, NULL);
}
}
inline Mutex::~Mutex() {
pthread_mutex_destroy(&mMutex);
}
inline status_t Mutex::lock() {
return -pthread_mutex_lock(&mMutex);
}
inline void Mutex::unlock() {
pthread_mutex_unlock(&mMutex);
}
inline status_t Mutex::tryLock() {
return -pthread_mutex_trylock(&mMutex);
}
#endif // HAVE_PTHREADS
 

也就是说如果定义了HAVE_PTHREADS宏,就有Mutex的相关方法实现,如果没有定义这个宏,Mutex的方法又是如何实现的,下面看看frameworks/base/libs/utils/Threads.cpp中的代码:
#if defined(HAVE_PTHREADS)
// implemented as inlines in threads.h
#elif defined(HAVE_WIN32_THREADS)
Mutex::Mutex()
{
HANDLE hMutex;
assert(sizeof(hMutex) == sizeof(mState));
hMutex = CreateMutex(NULL, FALSE, NULL);
mState = (void*) hMutex;
}
Mutex::Mutex(const char* name)
{
// XXX: name not used for now
HANDLE hMutex;
assert(sizeof(hMutex) == sizeof(mState));
hMutex = CreateMutex(NULL, FALSE, NULL);
mState = (void*) hMutex;
}
Mutex::Mutex(int type, const char* name)
{
// XXX: type and name not used for now
HANDLE hMutex;
assert(sizeof(hMutex) ==
1ff8
sizeof(mState));
hMutex = CreateMutex(NULL, FALSE, NULL);
mState = (void*) hMutex;
}
Mutex::~Mutex()
{
CloseHandle((HANDLE) mState);
}
status_t Mutex::lock()
{
DWORD dwWaitResult;
dwWaitResult = WaitForSingleObject((HANDLE) mState, INFINITE);
return dwWaitResult != WAIT_OBJECT_0 ? -1 : NO_ERROR;
}
void Mutex::unlock()
{
if (!ReleaseMutex((HANDLE) mState))
LOG(LOG_WARN, "thread", "WARNING: bad result from unlocking mutex/n");
}
status_t Mutex::tryLock()
{
DWORD dwWaitResult;
dwWaitResult = WaitForSingleObject((HANDLE) mState, 0);
if (dwWaitResult != WAIT_OBJECT_0 && dwWaitResult != WAIT_TIMEOUT)
LOG(LOG_WARN, "thread", "WARNING: bad result from try-locking mutex/n");
return (dwWaitResult == WAIT_OBJECT_0) ? 0 : -1;
}
#else
#error "Somebody forgot to implement threads for this platform."
#endif
 
也就是说,要么定义HAVE_PTHREADS宏,要么定义HAVE_WIN32_THREADS宏,否则,Mutex类的方法就没有实现代码。对于andorid来说,需要定义HAVE_PTHREADS宏。从上面的代码中还可以看出,android的线程实现实际上还是使用了pthread库,只是在上面进行了一个封装。在Android.mk中增加下面一条语句,问题解决:
LOCAL_CXXFLAGS := -DHAVE_PTHREADS
 

4. jni函数名带下划线,结果出错,将函数名的下划线去掉,解决问题。

 

 

原帖地址:http://blog.csdn.net/keensword007/archive/2010/07/08/5720636.aspx

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息