回调通常用仅含一个方法的接口表示
假如有个C语言接口的SDK函数,用于注册帧回调,当相机拍摄到一帧照片时,SDK调用用户注册的回调函数对这块图像帧进行处理(一般就是将其压缩编码成jpg码流)。它的声明长这样
MV_CAMCTRL_API int __stdcall MV_CC_RegisterImageCallBackEx(void* handle,
void(__stdcall* cbOutput)(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser),
void* pUser);
用JNAerator将上述声明转换成一个JNA Library方法和一个JNA Callback
int MV_CC_RegisterImageCallBackEx(Pointer handle, MV_CC_RegisterImageCallBackEx_cbOutput_callback cbOutput, Pointer pUser);
public interface MV_CC_RegisterImageCallBackEx_cbOutput_callback extends Callback {
void apply(Pointer pData, MV_FRAME_OUT_INFO_EX pFrameInfo, Pointer pUser);
};
回调通常以匿名内部类的形式注册
注意,不要先定义一个子类去继承MV_CC_RegisterImageCallBackEx_cbOutput_callback
接口,然后将子类实例传递给注册函数MV_CC_RegisterImageCallBackEx
,这在JDK 11上会报错
Exception in thread "main" java.lang.ClassCastException: class com.lanplus.HikJnaCamera$CaptureCallback cannot be cast to class com.lanplus.HikLibrary$MV_CC_RegisterImageCallBackEx_cbOutput_callback (com.lanplus.HikJnaCamera$CaptureCallback and com.lanplus.HikLibrary$MV_CC_RegisterImageCallBackEx_cbOutput_callback are in unnamed module of loader 'app')
官方教程也提示了
The simplest usage resembles using anonymous inner classes to register event listeners.
所以只能定义一个匿名内部类
// 定义回调
private HikLibrary.MV_CC_RegisterImageCallBackEx_cbOutput_callback captureCallback
= (Pointer pData, MV_FRAME_OUT_INFO_EX frameInfo, Pointer handle) -> {
String cameraName = mCameraNames.get(handle);
// ...
}
};
// 注册回调
int res_reg_cb = HikLibrary.INSTANCE.MV_CC_RegisterImageCallBackEx(handle.getValue(),
captureCallback, camera.mPtrRef.getValue());
回调通常在另一个线程里执行
对于相机,SDK通常会启动一个子线程,不停地从相机提取帧到缓冲区,然后执行用户回调,此时回调函数是在子线程中运行的,运行完毕后通常要告诉主线程结果,这就牵扯到线程同步。
关于此类话题的文章很多,不再赘述。