3

所以我想构建一个可扩展的 android 应用程序,开发人员可以在其中添加“CustomDevice”类,主程序将自动运行它们而无需编辑现有代码。

我已经阅读了有关服务提供者接口的信息,并认为这将是一个很好的解决方法。

所以我对其进行了测试并创建了一个名为“ICustomDevice”的接口,自定义设备类有望实现。

我创建了一个名为“DummyDevice”的类,它实现了 ICustomDevice。

DummyDevice 和 ICustomDevice 都在同一个包“CustomDevicePackage”中。

所以在我的主程序中,我运行以下命令。

    ServiceLoader<ICustomDevice> loader = ServiceLoader.load(ICustomDevice.class);
    Iterator<ICustomDevice> devices = loader.iterator();
    System.out.println("Does it have devices? " + devices.hasNext());

它总是返回 false,这意味着它没有找到“DummyDevice”

在我的 Eclipse 项目中,我在“src”创建了一个名为 META-INF 的文件夹,并在其下创建了一个名为“services”的子文件夹。

“服务”有一个名为“CustomDevicePackage.ICustomDevice”的文件,其中包含一行内容“CustomDevicePackage.DummyDevice”。

我做对了吗?我看到的每个关于 SPI 的例子都是关于加载 JARS。我没有加载 JAR,我正在尝试在同一个项目中运行一个类。此方法是否仅适用于加载 JAR?我希望我的程序支持加载本地子类和外部 JAR。

4

3 回答 3

0

我将此添加为答案,但保留先前的“答案”以提供此解决方法的扩展代码详细信息。我正在努力将先前的答案结果作为错误报告给 Google。

因为 java.util.ServiceLoader 的 Android 实现被破坏(即使 System.getSecurityManager() == null 也总是使用 AccessController.getContext() 填充内部 java.security.AccessControlContext 字段),解决方法是通过以下方式创建自己的 ServiceLoader 类将在 OpenJDK for Java 8 中找到的代码复制到您的类中,添加 java.util 所需的特定导入而不使用 import java.util.*;,并在您的代码中调用该 ServiceLoader(您必须完全引用您创建的 ServiceLoader含糊不清)。

这并不优雅,但它是一种有效的功能解决方法!此外,您需要在 ServiceLoader.load() 调用中使用 ClassLoader。该 ClassLoader 要么必须是 YourClass.class.getClassLoader(),要么必须是类的 ClassLoader 的子 ClassLoader。

于 2019-01-28T12:46:08.910 回答
0

虽然这是一个旧帖子,但这可能对其他人仍有一些帮助:

当我运行或调试包含 ServiceLoader 类的项目时,我必须将 META-INF/services 文件夹放入 Eclipse 中的 src/ 文件夹中。如果我尝试将项目导出为 Runnable jar 并尝试将该类与服务加载器一起使用,它永远不会起作用。当我检查 jar 并解压缩它时,我发现了 src/META-INF/services 下的文件夹。只有当我也直接在jar的根目录中添加了META-INF文件夹时,它才开始起作用。

虽然在 Eclipse 中我还没有找到一个修复程序,以确保它被正确导出......也许一个 ANT 脚本可以解决这个问题,但到目前为止没有尝试过......

于 2021-11-12T13:39:58.263 回答
-1

这是一个答案:

在某些时候,Android 删除了 ServiceLoader 中的 AccessControlContext 字段,现在 ServiceLoader 可以正常工作。正如我的评论所表明的,这可以使用带有 Android Studio 的“开箱即用”OREO (API 26) Intel Atom x86 仿真器(也是全新下载)来重现。24 小时后,ServiceLoader 不再包含 acc 字段(如使用相同模拟器的 Android Studio 调试器所示)。追溯到 API 24 的 Android SDK 不显示 acc 字段。

根据目前维护 ServiceLoader 代码的 Android 开发人员:他不知道 ServiceLoader 曾经在 Android 中拥有 acc 字段(正如我们能够重现的那样),并认为调试器/模拟器可能一直在使用 JDK 代码(但我展示了OpenJDK 代码正常工作)。在此过程中,错误的代码已更新,我不再能够重现。

确保您的操作系统是最新的,并且您应该不再看到这种现象。

于 2019-01-28T06:36:52.063 回答