当前位置:   article > 正文

Android 服务动态发现 SPA 之 Auto Service_auto-service

auto-service

转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/125859181
本文出自【赵彦军的博客】

SPI

SPI(Service Provider Interface)是 Java 提供的一种动态服务发现机制。通过SPI 机制,我们可以直接跨模块查找到想要的接口实现类,从而避免不必要的模块间依赖,降低模块之间的耦合性

Java 内置的 SPI 机制是通过 ServiceLoader 查找某个接口的所有实现类,并实例化。

每个需要实例化模块下需要以该接口的全限定名(包名+类名)为文件名放到 resources/META-INF/services/ 目录下,然后将他的实现类的全限定名按行依次写到该文件中。

1、创建接口类 StudentInterface

public interface StudentInterface {
    void eat(String name);
}
  • 1
  • 2
  • 3

2、创建接口实现类 StudentImpl

package com.zyj.demo;

import android.util.Log;

public class StudentImpl implements StudentInterface {

    @Override
    public void eat(String name) {
        Log.d("yu--", "" + name);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

StudentImpl 类的全路径为 : com.zyj.demo.StudentImpl

在这里插入图片描述

3、创建目录

  • main 目录下,创建 resources 目录
  • resources 目录下,创建 META-INF 目录
  • META-INF 目录下,创建 service 目录

service 目录下,创建 com.zyj.demo.StudentInterface 文件

文件的内容为:com.zyj.demo.StudentImpl

在这里插入图片描述
4、ServiceLoader 发现服务

接口可以有多个实现类,所以返回值是一个集合

//发现服务,接口可以有多个实现类,所以返回值是一个集合
ServiceLoader<StudentInterface> serviceLoader = ServiceLoader.load(StudentInterface.class);
        
//遍历服务
for (StudentInterface impl : serviceLoader) {
    impl.eat("zyj");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

总结

  • 动态服务发现机制,可以很好的解耦,不必直接依赖接口实现类。
  • ServiceLoader.load 每次都会创建一个新对象。生命周期用完即销毁
  • 缺点也很明显,要手动往 resources/META-INF/services/ 写入文件。

有没有一种自动写入的工具,可以解放双手?

有的,下面我们就介绍 auto-service

auto-service

auto-service 是 google 出品的自动发现服务工具 ,是 SPA 的一种方式。

  • SPA :Service Pool for Android

依赖:

 annotationProcessor 'com.google.auto.service:auto-service:1.0'
 implementation 'com.google.auto.service:auto-service-annotations:1.0'
  • 1
  • 2

我们只需要在 接口的实现类上,加上 @AutoService 注解,就可以了。

@AutoService(StudentInterface.class)
public class StudentImpl implements StudentInterface {

    @Override
    public void eat(String name) {
        Log.d("yu--", "" + name);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

发现服务,还是需要 ServiceLoader.load ,这个跟 Java 使用的是一致的。

//发现服务,接口可以有多个实现类,所以返回值是一个集合
ServiceLoader<StudentInterface> serviceLoader = ServiceLoader.load(StudentInterface.class);
        
//遍历服务
for (StudentInterface impl : serviceLoader) {
    impl.eat("zyj");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

总结

auto-service 的优势是,自动的往 resources/META-INF/services/ 写入文件,解放了双手,666666

我们看一眼这个目录,在 build 目录可以看到

在这里插入图片描述

识别多个服务

由于接口可以有多个实现类,所以我们通过 ServiceLoader.load(StudentInterface.class); 有可能有多个实例,我们如何区分自己需要的哪一个。

impl.getClass().getSimpleName() 可以获取实现类的名字。如下:

    void test() {
        ServiceLoader<StudentInterface> serviceLoader = ServiceLoader.load(StudentInterface.class, StudentInterface.class.getClassLoader());
        for (StudentInterface impl : serviceLoader) {

            if (impl.getClass().getSimpleName().equals("StudentImpl")) {
                //这就是我们的需要的服务
                impl.eat("zyj");
            }
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

实例作用域问题

即使用了 auto-service ,也不能解决实例作用域问题,如果需要全局使用,就需要自己实现单例了,这里不再展开。

SPA应用实战1 —— 子模块如何获取主模块的BuildConfig信息

多模块开发/组件化开发过程中,主模块(plugin为com.android.application的模块,一般指app模块)可以依赖任何模块,但是子模块无法依赖主模块,如果子模块想拿主模块的内容要怎么办呢? 下面演示如何通过Spa来获取主模块的Context和BuildConfig中的内容。

先在接口层定义一个BuildService

public interface BuildService {
    String buglyId(); // build.gradle中使用buildConfigField定义的buglyId

    boolean debuggable();

    String versionName();

    int versionCode();

    String applicationId();

    String buildType();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在app模块中,实现这个service接口并使用 @AutoService 标记

BuildServiceImpl.java

@AutoService(BuildService.class)
public class BuildServiceImpl implements BuildService {
    @Override
    public String buglyId() {
        return BuildConfig.BUGLY_ID;
    }

    @Override
    public boolean debuggable() {
        return BuildConfig.DEBUG;
    }

    @Override
    public String versionName() {
        return BuildConfig.VERSION_NAME;
    }

    @Override
    public int versionCode() {
        return BuildConfig.VERSION_CODE;
    }

    @Override
    public String applicationId() {
        return BuildConfig.APPLICATION_ID;
    }

    @Override
    public String buildType() {
        return BuildConfig.BUILD_TYPE;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

准备工作已经完成,现在我们在pages模块的BuildInfoActivity中应用它

public class BuildInfoActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        BuildInfoPageBinding viewBinding = BuildInfoPageBinding.inflate(LayoutInflater.from(this));
        setContentView(viewBinding.getRoot());

        BuildService buildService = Spa.getService(BuildService.class);
        viewBinding.applicationId.setText("applicationId: " + buildService.applicationId());
        viewBinding.versionName.setText("versionName: " + buildService.versionName());
        viewBinding.versionCode.setText("versionCode: " + buildService.versionCode() + "");
        viewBinding.buildType.setText("buildType: " + buildService.buildType());
        viewBinding.debuggable.setText("debuggable: " + buildService.debuggable());
        viewBinding.buglyId.setText("buglyId:" + buildService.buglyId());
    }
}}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Auto Service 源码

https://github.com/google/auto/tree/master/service

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

闽ICP备14008679号