当前位置:   article > 正文

Android 中使用 ServiceLoader、AutoService 摔坑记录_auto-service 只添加annotationprocessor

auto-service 只添加annotationprocessor

 

ServiceLoader Demo:https://github.com/mengzhinan/ServiceLoader_test

AutoService Demo:https://github.com/mengzhinan/AutoService_test

 

对 ServiceLoader 和 AutoService 早有耳闻,因各种原因而未对相关技术深入了解。

这两天在整理二者时踩到了无数硬坑,浏览器搜索发现全世界都是某一篇文章的集聚性传播,无法解决我的问题。

耗时 2 天死磕终于完成 Demo,并收获无数坑,现记录于此回报社会。

 

如果想对项目业务之间进行解耦、模块化开发;能使业务组件之间没有强依赖,彼此互相隐藏;且能够随时剔除某一个业务而不影响其他部分。就需要用到组件间通过接口进行业务交叉通讯了。如下图:

1、app 层与下层通讯通过接口,当业务变动需要剔除 A 业务时,对整个工程丝毫不需要修改变动。但是 app 层需要依赖 A 业务组件,目的是为了把代码打进输出包,而非代码层面的依赖调用。

2、A、B 业务层之间互相隐藏,避免业务调用耦合太高。

3、interface 中间层起到上下层隔离和联系作用,方便业务之间的交互。

上图即 Demo 的代码结构,参考 Demo。

 

一、环境说明:

1、Kotlin 开发,版本 1.3.72

2、AS 版本: 4.0

3、Gradle 版本:6.1.1

4、JDK 版本:1.8.0_192

即全部为最新版本,不存在网上说的版本兼容问题。

 

二、ServiceLoader 使用。

在 app 层通过 ServiceLoader.load 方法,扫描 /resources/META-INF/services/packageName.InterfaceName 文件名和内容,找到接口对应的实现类,然后调用。

按照上图的代码结构,还需要在 A 和 B 组件内新建对应的接口和实现类映射文件。简单不多说了,具体依赖和diamante细节看 Demo。

 

三、AutoService 使用。

在上述 Demo 基础上,你会发现还要我们手动新建 /resources/META-INF/... 映射文件,太麻烦了还容易写错。故 Google 爹爹给我们提供了 AutoServcie 工具,通过标记注解,然后使用注解处理器扫描数注解,并代替我们生成  /resources/META-INF/... 文件。其他的与上面方式一样。 代码细节参考 DEMO。

在试验 AutoService 过程中遇到的坑:

1、只在使用到 @AutoService 注解的模块中添加 AutoService 依赖。

注意:下面两行代码不可缺少,否则运行无效果的。

既然使用了 AutoService,就不需要新建 /resources/META-INF/servcies/... 映射文件了。

AutoServcieProcessor 的映射文件,Google 爹爹已经在依赖库中帮你做了。

  1. // 依赖 autoService 库
  2. implementation 'com.google.auto.service:auto-service:1.0-rc7'
  3. annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'

 2、注意,新建 Android Project 时,默认的 minSdkVersion = 16。此处需要修改可执行的 app 模块 minSdkVersion = 26,否则运行报如下问题。

Invoke-customs are only supported starting with Android O (--min-api 26)

  1. Invoke-customs are only supported starting with Android O (--min-api 26)
  2. Stack trace:
  3. com.android.tools.r8.a: Invoke-customs are only supported starting with Android O (--min-api 26)
  4. at com.android.tools.r8.dex.r.a(:289)
  5. at com.android.tools.r8.dex.r.a(:98)
  6. at com.android.tools.r8.dex.r.b(:188)
  7. at com.android.tools.r8.dex.b.a(:63)
  8. at com.google.common.util.concurrent.TrustedListenableFutureTask$TrustedFutureInterruptibleTask.runInterruptibly(TrustedListenableFutureTask.java:125)
  9. at com.google.common.util.concurrent.InterruptibleTask.run(InterruptibleTask.java:69)
  10. at com.google.common.util.concurrent.TrustedListenableFutureTask.run(TrustedListenableFutureTask.java:78)
  11. at com.google.common.util.concurrent.MoreExecutors$DirectExecutorService.execute(MoreExecutors.java:322)
  12. at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:134)
  13. at com.google.common.util.concurrent.AbstractListeningExecutorService.submit(AbstractListeningExecutorService.java:66)
  14. at com.google.common.util.concurrent.AbstractListeningExecutorService.submit(AbstractListeningExecutorService.java:36)
  15. at com.android.tools.r8.dex.b.b(:46)
  16. at com.android.tools.r8.D8.d(:87)
  17. at com.android.tools.r8.D8.b(:1)
  18. at com.android.tools.r8.utils.W.a(:30)
  19. at com.android.tools.r8.D8.run(:11)
  20. at com.android.builder.dexing.D8DexArchiveBuilder.convert(D8DexArchiveBuilder.java:116)
  21. at com.android.build.gradle.internal.dependency.BaseDexingTransform.process(DexingTransform.kt:296)
  22. at com.android.build.gradle.internal.dependency.BaseDexingTransform.processNonIncrementally(DexingTransform.kt:243)
  23. at com.android.build.gradle.internal.dependency.BaseDexingTransform.doTransform(DexingTransform.kt:153)
  24. at com.android.build.gradle.internal.dependency.BaseDexingTransform.access$doTransform(DexingTransform.kt:69)
  25. at com.android.build.gradle.internal.dependency.BaseDexingTransform$transform$1.invoke(DexingTransform.kt:104)
  26. ....................................................
  27. at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
  28. at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
  29. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
  30. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
  31. at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
  32. at java.lang.Thread.run(Thread.java:748)
  33. Suppressed: java.util.concurrent.ExecutionException: com.android.tools.r8.a: Invoke-customs are only supported starting with Android O (--min-api 26)
  34. at com.google.common.util.concurrent.AbstractFuture.getDoneValue(AbstractFuture.java:552)
  35. at com.google.common.util.concurrent.AbstractFuture.get(AbstractFuture.java:513)
  36. at com.google.common.util.concurrent.FluentFuture$TrustedFuture.get(FluentFuture.java:86)
  37. at com.android.tools.r8.utils.S0.a(:14)
  38. at com.android.tools.r8.dex.b.b(:101)
  39. ... 120 more
  40. [CIRCULAR REFERENCE:com.android.tools.r8.a: Invoke-customs are only supported starting with Android O (--min-api 26)]

3、发现现在使用 AS 新建 Java 类时,默认没有 public 关键字。此处使用 ServiceLoader.load 调用的接口的实现类必须是 public 类型的,且必须有公共无参的构造函数,否则报下面错误:

java.util.ServiceConfigurationError: com.duke.libinterface.IBook: Provider com.duke.liba.BookPythonImpl could not be instantiated

  1. 2020-06-21 18:31:20.459 9537-9537/com.duke.autoservice_test E/AndroidRuntime: FATAL EXCEPTION: main
  2. Process: com.duke.autoservice_test, PID: 9537
  3. java.util.ServiceConfigurationError: com.duke.libinterface.IBook:
  4. Provider com.duke.liba.BookPythonImpl could not be instantiated
  5. at java.util.ServiceLoader.fail(ServiceLoader.java:233)
  6. at java.util.ServiceLoader.access$100(ServiceLoader.java:183)
  7. at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:392)
  8. at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:416)
  9. at java.util.ServiceLoader$1.next(ServiceLoader.java:494)
  10. at com.duke.autoservice_test.ServiceLoaderHelper.loadServices(ServiceLoaderHelper.kt:21)
  11. at com.duke.autoservice_test.MainActivity.onResume(MainActivity.kt:27)
  12. at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1456)
  13. at android.app.Activity.performResume(Activity.java:8119)
  14. at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4333)
  15. at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4375)
  16. at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
  17. at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
  18. at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
  19. at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2049)
  20. at android.os.Handler.dispatchMessage(Handler.java:106)
  21. at android.os.Looper.loop(Looper.java:223)
  22. at android.app.ActivityThread.main(ActivityThread.java:7523)
  23. at java.lang.reflect.Method.invoke(Native Method)
  24. at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
  25. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
  26. Caused by: java.lang.IllegalAccessException: java.lang.Class<com.duke.liba.BookPythonImpl> is not accessible from java.lang.Class<java.util.ServiceLoader$LazyIterator>
  27. at java.lang.Class.newInstance(Native Method)

同时不要忘记了使用 AutoService 注解,正确代码:

  1. @AutoService(IBook.class)
  2. public class BookTCPIPImpl implements IBook {
  3. @Nullable
  4. @Override
  5. public String getBookName() {
  6. return "book b";
  7. }
  8. }

 

4、最后天坑,不报错也无效果。看我的 Demo 后会发现,虽然代码不多,但是都是使用 kotlin 写的,只有接口的实现类是用 java 写的(如上面实现类代码)。否则的话运行无效果,还会让你怀疑代码写错了、环境配置有问题。

为什么实现类不能用 kotlin 写?我不知道,可能是 kotlin 版本的问题、AS 的问题、AutoServcie 的问题、ServcieLoader 的问题。这个坑卡了我 2 天,否则不会消耗我那么久的时间,本来技术点就不难。

大佬不信?你试试,把上面的实现类自动转换为 kotlin 代码后再运行。

 

ServiceLoader Demo:https://github.com/mengzhinan/ServiceLoader_test

AutoService Demo:https://github.com/mengzhinan/AutoService_test

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/887269
推荐阅读
相关标签
  

闽ICP备14008679号