在 Delphi 中实施 Java/Android 的 callback/listeners

Implementing Java/Android's callback/listeners in Delphi

我正在尝试在 Delphi 10.2 Tokyo 中创建一个 Android 应用程序,它使用了 Camera2 API. I used Java2OP to create the interfaces that I need. Some of these interfaces are for callback/listeners. For example CameraDevice.StateCallback,Java2OP 已将其转换为:

JCameraDevice_StateCallbackClass = interface(JObjectClass)
    ['{3F5A7394-FD15-439C-9BFB-DF8D43F9F930}']
    {class} function _GetERROR_CAMERA_DEVICE: Integer; cdecl;
    {class} function _GetERROR_CAMERA_DISABLED: Integer; cdecl;
    {class} function _GetERROR_CAMERA_IN_USE: Integer; cdecl;
    {class} function _GetERROR_CAMERA_SERVICE: Integer; cdecl;
    {class} function _GetERROR_MAX_CAMERAS_IN_USE: Integer; cdecl;
    {class} function init: JCameraDevice_StateCallback; cdecl;
    {class} property ERROR_CAMERA_DEVICE: Integer read _GetERROR_CAMERA_DEVICE;
    {class} property ERROR_CAMERA_DISABLED: Integer read _GetERROR_CAMERA_DISABLED;
    {class} property ERROR_CAMERA_IN_USE: Integer read _GetERROR_CAMERA_IN_USE;
    {class} property ERROR_CAMERA_SERVICE: Integer read _GetERROR_CAMERA_SERVICE;
    {class} property ERROR_MAX_CAMERAS_IN_USE: Integer read _GetERROR_MAX_CAMERAS_IN_USE;
  end;

  [JavaSignature('android/hardware/camera2/CameraDevice$StateCallback')]
  JCameraDevice_StateCallback = interface(JObject)
    ['{3A3944F5-A71F-4CD6-98C6-04B8D65C3B52}']
    procedure onClosed(camera: JCameraDevice); cdecl;//Deprecated
    procedure onDisconnected(camera: JCameraDevice); cdecl;//Deprecated
    procedure onError(camera: JCameraDevice; error: Integer); cdecl;//Deprecated
    procedure onOpened(camera: JCameraDevice); cdecl;//Deprecated
  end;
  TJCameraDevice_StateCallback = class(TJavaGenericImport<JCameraDevice_StateCallbackClass, JCameraDevice_StateCallback>) end;

据我了解,我应该将 TJavaLocal 与我想用作 callback/listener 的接口结合使用(在本例中为 JCameraDevice_StateCallbackClass)。这是我所做的: 单位 CamDevStateCallback;

interface

uses
  Androidapi.JNIBridge, android.hardware.camera2;

type
  TCamera2Event = procedure(camera: JCameraDevice) of object;
  TCamera2ErrorEvent = procedure(camera: JCameraDevice; error: Integer) of object;

  TCamDevStateCallback = class(TJavaLocal, JCameraDevice_StateCallback)

  protected
    FOnClosed: TCamera2Event;
    FOnDisconnected: TCamera2Event;
    FOnError: TCamera2ErrorEvent;
    FOnOpen: TCamera2Event;

  public
    procedure onClosed(camera: JCameraDevice); cdecl;
    procedure onDisconnected(camera: JCameraDevice); cdecl;
    procedure onError(camera: JCameraDevice; error: Integer); cdecl;
    procedure onOpened(camera: JCameraDevice); cdecl;
    class function CreateNew(aOnOpen, aOnClosed, aOnDisconnected: TCamera2Event; aOnError: TCamera2ErrorEvent): JCameraDevice_StateCallback;
    property OnCameraClosed: TCamera2Event read FOnClosed write FOnClosed;
    property OnCameraDisconnected: TCamera2Event read FOnDisconnected write FOnDisconnected;
    property OnCameraError: TCamera2ErrorEvent read FOnError write FOnError;
    property OnCameraOpen: TCamera2Event read FOnOpen write FOnOpen;
  end;

implementation

{ TCamDevStateCallback }

class function TCamDevStateCallback.CreateNew(aOnOpen, aOnClosed, aOnDisconnected: TCamera2Event;
  aOnError: TCamera2ErrorEvent): JCameraDevice_StateCallback;
var
  tmpObj: TCamDevStateCallback;
begin
  tmpObj := TCamDevStateCallback.Create;
  tmpObj.OnCameraClosed := aOnClosed;
  tmpObj.OnCameraDisconnected := aOnDisconnected;
  tmpObj.OnCameraError := aOnError;
  tmpObj.OnCameraOpen := aOnOpen;
  Result := TJCameraDevice_StateCallback.Wrap((tmpObj as ILocalObject).GetObjectID);
end;

procedure TCamDevStateCallback.onClosed(camera: JCameraDevice);
begin
  if Assigned(FOnClosed) then
    FOnClosed(camera);
end;

procedure TCamDevStateCallback.onDisconnected(camera: JCameraDevice);
begin
  if Assigned(FOnDisconnected) then
    FOnDisconnected(camera);
end;

procedure TCamDevStateCallback.onError(camera: JCameraDevice; error: Integer);
begin
  if Assigned(FOnError) then
    FOnError(camera, error);
end;

procedure TCamDevStateCallback.onOpened(camera: JCameraDevice);
begin
  if Assigned(FOnOpen) then
    FOnOpen(camera);
end;

end.

此代码无法编译,因为它抱怨 equalstoString 与之前的声明不同,并且 getClassnotifynotifyAllwait 不见了。

android.hardware.camera2.pas由Java2OP创建,包含[=23=的接口定义] 等等。

正如@DaveNottage 所指出的,这里的潜在问题是 CameraDevice.StateCallback 不是 Java 侦听器接口,而是 Java 回调 class(尽管是abstract class 因此在某些方面类似于接口,但不是接口)。

因为它不是 Java 接口,所以它 不是 使用 TJavaLocal 实现的候选接口,尽管在 Delphi 中它由接口 表示(因为所有 Java 接口和 class 都是)。

TJavaLocal 用于实现 Java 接口,通常是侦听器接口。它不提供从 Java class(甚至是抽象 Java class)继承的方法。

线索是Java2OP创建的重要接口继承自JObject表明它是Java基于Object的一部分class 层次结构。导入时的侦听器接口继承自 IJavaInstance.

Delphi 不支持从 Android Java classes 继承(与其 iOS 支持相比,其中 Delphi 是否支持从 Objective-C classes 继承,这要归功于 Objective-C 是一个本地系统,不像 Android 的托管 Java虚拟机系统)