Vik*_*yan 4 java eclipse java-native-interface types
我有.so(共享库)用C++编写,让我们称之为function.so,其中我实现了不同的函数,这里是一些函数的列表:
1. unsigned long Initialize(void* userData);
2. unsigned long Uninitialize(void);
3. unsigned long DeviceOpen( unsigned long id, unsigned long* device);
4. unsigned long DeviceClose( unsigned long device );
Run Code Online (Sandbox Code Playgroud)
等等 ...
我想在我的java应用程序中使用这个库的(functional.so)功能.为此我在我的android应用程序项目文件夹中创建jni文件夹并放置文件:
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Test_library
LOCAL_SRC_FILES := Test_library.c
## Linking functionality library
LOCAL_LDLIBS := -lfunctionality
include $(BUILD_SHARED_LIBRARY)
Run Code Online (Sandbox Code Playgroud)Test_library.c
#include <string.h>
#include <jni.h>
#include "Test_library.h"
jint Java_com_Dsm_Test_DsmLibraryTest_vtUninitialize(JNIEnv* env, jobject thiz) {
return Uninitialize( );
}
jint Java_com_Dsm_Test_DsmLibraryTest_vtDeviceClose(JNIEnv* env, jobject thiz, jint hDevice) {
return DeviceClose( hDevice );
}
Run Code Online (Sandbox Code Playgroud)Test_library.h
其中A头文件初始化,未初始化,DeviceOpen,DeviceClose函数声明.
在此之后,我运行ndk-build并创建一个Test_library.so库并将其加载到我的java应用程序中并使用它们:
// Some code
public native int Uninitialize( );
public native int DeviceClose( int hDevice );
static {
System.loadLibrary("Test_library");
}
Run Code Online (Sandbox Code Playgroud)
一切都运行良好.之后我想添加其他两个功能
1. unsigned long Initialize(void* userData);
2. unsigned long DeviceOpen( unsigned long id, unsigned long* device);
Run Code Online (Sandbox Code Playgroud)
`
感谢帮助.
您可以使用jlong将指针(或指针指针等)传递回Java.Java代码将无法将其用于任何事情,除了将其作为参数传递给您的其他方法之外; 但通常这就是你真正想要的.另一方面,如果您希望Initialize()使用Java设置数据进行调用,那么这void *是不合适的; 您需要使用Java类,并在JNI中使用反射来获取所需的信息.
好听的,你可以包装malloc()和free():
jlong Java_c_utils_malloc(JNIEnv* env, jclass clazz, jint size) {
return (jlong) malloc(size);
}
void Java_c_utils_free(JNIEnv* env, jclass clazz, jlong ptr) {
free((void *) ptr);
}
Run Code Online (Sandbox Code Playgroud)
然后在Java中使用它们(无效!):
long ptr = utils.malloc(100);
// Store ptr for a while
utils.free(ptr);
Run Code Online (Sandbox Code Playgroud)
现在,如果我们将一些需要一块内存作为参数的其他函数包装起来,我们也可以将它们包装起来,让它们接受一个jlong参数,就像free()这样.Java变量ptr表示内存地址的事实在Java中是完全不透明的,但它仍然有用.
Java的窗口系统实现(即,AWT,SWT)使用同样的东西来将本机窗口小部件句柄与Java组件相关联.
现在,如果你希望你Initialize()能够从Java中获取有用的参数,那么a void *不会削减它.您需要编写自己的方法来接受Java对象作为参数; 这是允许您在Java中操作对象的唯一方法.
我不想在这里复制所有代码,但Sun的JNI教程就在这里.这是关于调用Java对象的任意方法的部分(this对象或作为参数传递给方法的对象),这是访问对象字段的类似部分.
你想要做的是:对于void*函数,使用直接字节缓冲区.在Java方面:
native long initialize(java.nio.ByteBuffer userData);
Run Code Online (Sandbox Code Playgroud)
调用方法时,请确保分配直接的ByteBuffer(请参阅java.nio.ByteBuffer和JNI nio用法):
ByteBuffer myData = ByteBuffer.allocateDirect(size);
long res = initialize(myData);
Run Code Online (Sandbox Code Playgroud)
在C方面,你这样做:
unsigned long res = Initialize(env->GetDirectBufferAddress(env, buffer));
return (jlong)res;
Run Code Online (Sandbox Code Playgroud)
您可以使用ByteBuffer方法从Java端的缓冲区读取和写入.
您也可以在C侧分配字节缓冲区env->NewDirectByteBuffer(env, ptr, size.
现在,对于第二个函数,我假设unsigned long*参数用于返回结果.您可以使用相同的方法(直接ByteBuffers),但我会推荐一个不需要为这么小的值分配缓冲区的方法.
在Java方面:
native long deviceOpen(long id, long[] device);
Run Code Online (Sandbox Code Playgroud)
在C方面:
unsigned long c_device;
unsigned long res = DeviceOpen((unsigned long)j_id, &c_device);
env->SetLongArrayRegion(env, j_device, 0, 1, &c_device);
return (jlong)res;
Run Code Online (Sandbox Code Playgroud)
然后从Java调用该方法:
long[] deviceOut = new long[1];
long res = deviceOpen(id, deviceOut);
long device = deviceOut[0];
Run Code Online (Sandbox Code Playgroud)
有关JNI的数组访问的更多信息,请参阅JNI数组操作
| 归档时间: |
|
| 查看次数: |
9444 次 |
| 最近记录: |