回調通常用僅含一個方法的接口表示
假如有個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通常會啓動一個子線程,不停地從相機提取幀到緩衝區,然後執行用戶回調,此時回調函數是在子線程中運行的,運行完畢後通常要告訴主線程結果,這就牽扯到線程同步。
關於此類話題的文章很多,不再贅述。