首页 > 解决方案 > 如何在 Delphi 代码中捕获 java 异常

问题描述

我正在编写一个通过 JNI 访问 Google Drive API 的 Delphi/Android 应用程序。我需要调用 Java 方法并捕获发生的任何异常。那么如何在 Delphi 中捕获 Java 异常呢?我还需要异常对象来从中获取意图。

我在网上搜索了一些关于 Env ExceptionCheck 的信息。我想我可以通过这种方式获取异常类,但是如何获取异常对象呢?

Java 代码如下所示:

try {
    new Builder(
        AndroidHttp.newCompatibleTransport(),
        new GsonFactory(),
        DriveLoginFragment.this.mCredential
    ).setApplicationName("My App").build();
}
catch (UserRecoverableAuthIOException e) {
    DriveLoginFragment.this.startActivityForResult(
        e.getIntent(),
        REQUEST_ACCOUNT_PICKER);
    return null;
}

Delphi 代码如下所示:

Drive := TJDrive_Builder.JavaClass.init(
  TJAndroidHttp.JavaClass.newCompatibleTransport,
  TJGsonFactory.JavaClass.init,
  GoogleAccountCredential
)
.setApplicationName(StringToJString('My app'))
.build;

标签: javaandroiddelphiexception

解决方案


我按照 Dave Nottage 的建议做了。我编写了一点java代码。

我用以下类制作了一个java库:

package com.softmagic.androidutils;

import java.lang.Thread.UncaughtExceptionHandler;

interface ExpListener {
    void onException(Thread thread, Throwable throwable);

}

public class DelphiHandleExceptions implements UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        listenerInt.onException(thread, throwable);
    }

    ExpListener listenerInt;

    public DelphiHandleExceptions(ExpListener listener) {

        listenerInt = listener;
    }

}

我通过java2op运行它,并得到以下信息:

unit AndroidApi.JNI.AndroidUtils;

interface

uses
  Androidapi.JNIBridge,
  Androidapi.JNI.JavaTypes;

type
// ===== Forward declarations =====

  Jandroidutils_BuildConfig = interface;//com.softmagic.androidutils.BuildConfig
  JDelphiHandleExceptions = interface;//com.softmagic.androidutils.DelphiHandleExceptions
  JExpListener = interface;//com.softmagic.androidutils.ExpListener

// ===== Interface declarations =====

  Jandroidutils_BuildConfigClass = interface(JObjectClass)
    ['{EE706AD2-1C35-46DF-BA16-6B6C82A32336}']
    {class} function _GetAPPLICATION_ID: JString; cdecl;
    {class} function _GetBUILD_TYPE: JString; cdecl;
    {class} function _GetDEBUG: Boolean; cdecl;
    {class} function _GetFLAVOR: JString; cdecl;
    {class} function _GetVERSION_CODE: Integer; cdecl;
    {class} function _GetVERSION_NAME: JString; cdecl;
    {class} function init: Jandroidutils_BuildConfig; cdecl;//Deprecated
    {class} property APPLICATION_ID: JString read _GetAPPLICATION_ID;
    {class} property BUILD_TYPE: JString read _GetBUILD_TYPE;
    {class} property DEBUG: Boolean read _GetDEBUG;
    {class} property FLAVOR: JString read _GetFLAVOR;
    {class} property VERSION_CODE: Integer read _GetVERSION_CODE;
    {class} property VERSION_NAME: JString read _GetVERSION_NAME;
  end;

  [JavaSignature('com/softmagic/androidutils/BuildConfig')]
  Jandroidutils_BuildConfig = interface(JObject)
    ['{2F38FDFA-A06E-486C-A2F1-9736596BFD14}']
  end;
  TJandroidutils_BuildConfig = class(TJavaGenericImport<Jandroidutils_BuildConfigClass, Jandroidutils_BuildConfig>) end;

  JDelphiHandleExceptionsClass = interface(JThread_UncaughtExceptionHandlerClass)
    ['{E39A8542-DF8B-4880-8286-C4BD9993F6CE}']
    {class} function init(P1: JExpListener): JDelphiHandleExceptions; cdecl;//Deprecated
    {class} procedure uncaughtException(P1: JThread; P2: JThrowable); cdecl;//Deprecated
  end;

  [JavaSignature('com/softmagic/androidutils/DelphiHandleExceptions')]
  JDelphiHandleExceptions = interface(JThread_UncaughtExceptionHandler)
    ['{B8AC378F-9FCA-4661-95E0-BA73736E6426}']
  end;
  TJDelphiHandleExceptions = class(TJavaGenericImport<JDelphiHandleExceptionsClass, JDelphiHandleExceptions>) end;

  JExpListenerClass = interface(IJavaClass)
    ['{AC1C06C0-B5D4-4952-9076-5AAAE941703C}']
  end;

  [JavaSignature('com/softmagic/androidutils/ExpListener')]
  JExpListener = interface(IJavaInstance)
    ['{DC8FC3DE-029F-4127-90AA-AABC2081B78B}']
    procedure onException(P1: JThread; P2: JThrowable); cdecl;//Deprecated
  end;
  TJExpListener = class(TJavaGenericImport<JExpListenerClass, JExpListener>) end;

implementation

procedure RegisterTypes;
begin
  TRegTypes.RegisterType('AndroidApi.JNI.AndroidUtils.Jandroidutils_BuildConfig', TypeInfo(AndroidApi.JNI.AndroidUtils.Jandroidutils_BuildConfig));
  TRegTypes.RegisterType('AndroidApi.JNI.AndroidUtils.JDelphiHandleExceptions', TypeInfo(AndroidApi.JNI.AndroidUtils.JDelphiHandleExceptions));
  TRegTypes.RegisterType('AndroidApi.JNI.AndroidUtils.JExpListener', TypeInfo(AndroidApi.JNI.AndroidUtils.JExpListener));
end;

initialization
  RegisterTypes;
end.

我做了以下声明:

   JavaExceptionListener: TJavaExceptionListener;
   DefUncaughtExceptionHandler: JThread_UncaughtExceptionHandler;
   DelphiHandleExceptions: JDelphiHandleExceptions;

在我的 FormCreate 方法中,我输入了:

   JavaExceptionListener := TJavaExceptionListener.Create;
   DefUncaughtExceptionHandler := TJThread.JavaClass.getDefaultUncaughtExceptionHandler;
   DelphiHandleExceptions := 
   TJDelphiHandleExceptions.JavaClass.init(JavaExceptionListener);
   TJThread.JavaClass.setDefaultUncaughtExceptionHandler(DelphiHandleExceptions);

我定义了监听器:

  TJavaExceptionListener = class(TJavaLocal, JExpListener)
    procedure onException(P1: JThread; P2: JThrowable); cdecl;
  end;

它的方法:

procedure TJavaExceptionListener.onException(P1: JThread; P2: JThrowable);
begin

  if TJNIResolver.IsInstanceOf(P2, TJUserRecoverableAuthIOException.GetClsID)
  then
     begin
        TAndroidHelper.Activity.startActivityForResult(TJUserRecoverableAuthIOException.Wrap(P2).getIntent, REQUEST_ACCOUNT_PICKER);
        Exit;
     end;

  DefUncaughtExceptionHandler.uncaughtException(P1, P2);

end;

我还没有测试过。我的应用程序尚未准备好进行测试。我认为这会奏效。


推荐阅读