Android組件化開發(fā)之SPI

Java SPI全稱Service Provider Interface,是Java提供的一套用來被第三方實現或者擴展的API,它可以用來啟用框架擴展和替換組件。實際上是“基于接口的編程+策略模式+配置文件”組合實現的動態(tài)加載機制.

ServiceLoader的使用

操作步驟:

1、定義一個接口文件

2、寫出多個該接口文件的實現

3、在 src/main/resources/ 下建立 /META-INF/services 目錄, 新增一個以接口命名的文件 , 內容是要接口的實現類全路徑

4、使用ServiceLoader類 來獲取到這些實現的接口

先創(chuàng)建一個interface的module。

1631428120(1).png

然后在其他的模塊實現這個接口,并在實現這個接口的module中創(chuàng)建一個resources文件夾,文件夾里建一個文件,文件名為(對應接口的全路徑 + 接口名),文件里面寫的內容則為其(實現類的全路徑+實現類名)。在操作過程中,遇到了一個坑,就是文件夾是兩級文件夾,我在操作的時候圖簡單,直接META-INF.services,結果導致通過ServiceLoader獲取實現類的時候,獲取為空。這里應該先創(chuàng)建一個文件夾,命名為META-INF,然后再在這個文件夾再創(chuàng)建一個文件夾,命名為services,雖然在AS上顯示仍然為META-INF.services,但是這是一個二級文件夾 ,而我那種做法只算以及文件夾。導致獲取不到文件里的內容。

1631428877(1).png

然后創(chuàng)建一個help類,其具體的實現為:


public class ServiceHelper {
    //針對一種接口多個實現類操作
    public static <T> List<T> getServices(Class<T> interfaceClass){
        ServiceLoader loader = ServiceLoader.load(interfaceClass);
        Iterator iterator = loader.iterator();
        List<T> list = new ArrayList<>();
        while (iterator.hasNext()){
            T t = (T) iterator.next();
            if (t != null){
                list.add(t);
            }
        }
        return list;
    }

    //針對一個接口一個實現類操作
    public static <T> T getService(Class<T> interfaceClass){
        ServiceLoader loader = ServiceLoader.load(interfaceClass);
        Iterator<T> iterator = loader.iterator();
        if (iterator.hasNext()){
            return (T) iterator.next();
        }else {
            return null;
        }
    }
}

然后在App模塊中調用,

AInterface aInterface =  ServiceHelper.getService(AInterface.class);
Log.e("zzf",aInterface + "");
BInterface bInterface = ServiceHelper.getService(BInterface.class);
Log.e("zzf",aInterface.getname() +"------------" + bInterface.getname());

1631340692(1).png
1631341048(1).png

這種方法在平常組件化開發(fā)中非常便利,但是每次都需要到/META-INF/services 目錄建立文件,不能動態(tài)添加。因此采用Google的@AutoService,他可以幫我們在編譯的時候動態(tài)去生成這些東西。

ServiceLoader + @AutoService的使用

添加依賴:

implementation 'com.google.auto.service:auto-service:1.0'
annotationProcessor 'com.google.auto.service:auto-service:1.0'

接口module不需要變,我們只需要在實現類進行改變一下即可:

@AutoService(CInterface.class)
public class C2Impl implements CInterface {
    @Override
    public String getName() {
        return "C2Impl";
    }
}

只需要在具體的實現類上面加上一個@AutoService注解,參數則為接口的class類。

然后在App模塊中調用,

List<CInterface> list = ServiceHelper.getServices(CInterface.class);
for (CInterface cInterface:list){
    Log.e("zzf",cInterface.getName());
}
ARouter

阿里的ARouter框架就是是借助了這種思想,它只需要我們的自己的接口繼承IProvider接口,

public interface BInterface extends IProvider {
    String getname();
}

然后在B模塊實現接口

@Route(path = "/user/BInterface")
public BImpl implements BInterface{
    @Override
    public String getname() {
        return "A2Impl";
    }
}

然后在其他模塊通過ARouter注解獲取實例

@Autowired//(name = "/user/BInterface")
    BImpl mBImpl;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ARouter.getInstance().inject(this);
        ...
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容