DJI Gimbal开发:如何获取硬件按键按下的回调事件
DJI OSMO云台硬件按键事件拦截实现方案
问题背景
基于Android Camera2 SDK开发相机应用,已集成DJI Mobile SDK,完成API密钥注册且收到REGISTRATION_SUCCESS回调,云台已通过蓝牙与手机正常连接。需要实现拦截云台自带硬件按键(录制键、快门键、变焦拨杆)的按下事件,触发应用内对应录制、拍照、变焦逻辑。
自行编写的测试代码无法收到按键回调,代码如下:
OSMOMobileHandheldController osmoMobileHandheldController = new OSMOMobileHandheldController(); osmoMobileHandheldController.setHardwareStateCallback(hardwareState -> { switch (hardwareState.getRecordAndShutterButtons()) { case IDLE: { Log.e(TAG, "getRecordAndShutterButtons IDLE"); break; } case RECORD_CLICK: { Log.e(TAG, "getRecordAndShutterButtons RECORD_CLICK"); break; } case SHUTTER_CLICK: { Log.e(TAG, "getRecordAndShutterButtons SHUTTER_CLICK"); break; } case SHUTTER_LONG_CLICK: { Log.e(TAG, "getRecordAndShutterButtons SHUTTER_LONG_CLICK"); break; } default: { Log.e(TAG, "getRecordAndShutterButtons UNKNOWN"); } } switch (hardwareState.getZoomState()) { case IDLE: { Log.e(TAG, "getZoomState IDLE"); break; } case ZOOM_IN: { Log.e(TAG, "getZoomState ZOOM_IN"); break; } case ZOOM_OUT: { Log.e(TAG, "getZoomState ZOOM_OUT"); break; } default: { Log.e(TAG, "getTriggerButton UNKNOWN"); } } });
失效原因
你手动构造OSMOMobileHandheldController实例的写法是错误的。DJI SDK中所有和硬件交互的组件实例都和实际连接的设备强绑定,自行new出来的对象只是空壳,没有和底层通信链路关联,自然无法收到硬件上报的任何状态。
正确实现方式
1. 监听设备连接状态,从连接的产品实例中获取控制器
SDK注册成功后,注册产品连接监听,在设备真正连接完成后,从产品对象中取出对应的手持控制器实例,不要自行构造:
// SDK注册成功回调中执行 DJISDKManager.getInstance().addProductConnectionListener(new ProductConnectionListener() { @Override public void onProductConnect(@Nullable BaseProduct baseProduct) { if (baseProduct instanceof HandheldProduct) { HandheldProduct handheld = (HandheldProduct) baseProduct; // 从真实连接的设备对象中获取控制器 HandheldController controller = handheld.getHandheldController(); if (controller != null) { bindHardwareKeyCallback(controller); } } } @Override public void onProductDisconnect(int errorCode) { // 设备断开时及时清空回调,避免内存泄漏 } });
2. 给控制器绑定硬件状态回调
拿到真实的控制器实例后,再设置硬件状态监听,即可正常收到按键事件:
private void bindHardwareKeyCallback(HandheldController controller) { controller.setHardwareStateCallback(hardwareState -> { // 处理录制、快门按键事件 switch (hardwareState.getRecordAndShutterButtons()) { case RECORD_CLICK: // 回调在子线程执行,操作UI/Camera2接口注意切换线程 mainHandler.post(() -> toggleLocalRecord()); break; case SHUTTER_CLICK: mainHandler.post(() -> takeLocalPhoto()); break; case SHUTTER_LONG_CLICK: // 对应长按快门的自定义逻辑 break; case IDLE: default: break; } // 处理变焦拨杆事件 switch (hardwareState.getZoomState()) { case ZOOM_IN: mainHandler.post(() -> adjustCameraZoom(true)); break; case ZOOM_OUT: mainHandler.post(() -> adjustCameraZoom(false)); break; case IDLE: default: break; } }); }
兼容注意事项
- 部分早期型号OSMO云台的固件版本不支持全量按键状态上报,接入前先通过
controller.getFirmwareVersion()确认固件版本符合要求 - 硬件状态回调默认执行在SDK内部子线程,操作Camera2接口、更新UI必须切换到对应线程
- 设备断开连接、页面销毁时主动调用
controller.setHardwareStateCallback(null)清空回调,避免内存泄漏 - 部分云台默认会将按键事件映射为系统音量键事件,如果上述回调无法收到事件,可以在对应Activity中重写
onKeyDown方法,拦截KEYCODE_VOLUME_UP、KEYCODE_VOLUME_DOWN事件做兼容处理
内容的提问来源于stack exchange,提问作者Walid
相关产品推荐
相关产品推荐

