如何在Delphi代码中捕获Java异常

4

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

我在网络上搜索并找到了一些关于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;

你能描述一下在获取异常对象后你打算做什么吗? - Dave Nottage
我想使用Intent启动一个活动。如果您查看Java代码,当它捕获到UserRecoverableAuthIOException时,它会从异常对象中获取Intent,并使用此Intent发出startActivityforResult。 - helgovic
可能可以在Thread类上使用setDefaultUncaughtExceptionHandler方法,主要问题是你需要传递一个继承自UncaughtExceptionHandler并覆盖uncaughtException方法的后代实例。这需要一些Java代码,因为目前无法在Delphi中完成Java类的后代。 - Dave Nottage
1个回答

0

我按照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;

我还没有测试过。我的应用程序还没有准备好进行测试。我认为这会起作用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接