当前位置:   article > 正文

Android组件化SPI_android spi

android spi

SPI是什么

SPI全称Service Provider Interface,是Java提供的一套用来被第三方实现或者扩展的API,它可以用来启用框架扩展和替换组件。

整体机制图如下:

Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制。
模块之间基于接口编程,模块之间不对实现类进行硬编码,实现解耦,而且实现可插拔替换。

解耦过程

场景:同时有多个同品类第三方SDK需要使用,实现统一的api接口,根据不同的条件路由到不同的SDK。

1.pluginManager方式

最初的实现方式:

从图中可以看出,3个module实现了同一个api,而APP强依赖了3个module。
怎么解耦呢?
APP并不想关心有多少个module实现了api,只关心调用的api接口。如图所示,我们增加manager来管理多个module。

从这个图来看,我们怎么进一步让manager和多个module进行解耦呢?可不可以使manager轻松一点呢?

让各个module自己来注册吧,manager负责动态加载呢?我们来看下实现的GitHub Demo-PluginManger

demoA实现接口api

class DemoImplA : ABaseApi {
    private val TAG = "DemoImpl"
    override fun init() {
        Log.d(TAG, "init DemoImplA")
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

AEnginePlugin 获取api对应的demo

public class AEnginePlugin implements IAEnginePlugin {
    @Override
    public ABaseApi getAEngineInstance() {
        return new DemoImplA();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

APluginManager 负责往EnginePluginManager里的map注册添加,manager负责load

public class APluginManager extends EnginePluginManager.HolderPlugin {
    private static final AEnginePlugin aEnginePlugin = new AEnginePlugin();
    @Override
    protected void configure() {
        registerService(IAEnginePlugin.class, aEnginePlugin);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
    private static String[] providers = new String[]{
            "com.ghp.impledemoa.APluginManager",
            "com.ghp.impledemob.BPluginManager",
            "com.ghp.impledemoc.CPluginManager"
    };

    private static final HashMap<Class, Object> classObjectHashMap = new HashMap<>(providers.length);

    public static <T> T service(Class<T> a2) {
        return (T) classObjectHashMap.get(a2);
    }

    static {
        loadRouter();
    }
    private static void loadRouter() {
        for (String provider : providers) {
            try {
                HolderPlugin basePlugin = (HolderPlugin) Class.forName(provider).newInstance();
                basePlugin.configure();
                Log.d("EnginePluginManager", provider + " loadRouter!");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    public abstract static class HolderPlugin {

        protected abstract void configure();

        protected static void registerService(Class c, Object object) {
            classObjectHashMap.put(c, object);
        }
    }
}
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

最终根据路由调用,具体代码参见GitHub Demo-PluginManger

EnginePluginManager.service(IAEnginePlugin.class).getAEngineInstance()

2.Annotation方式

到这里已经实现APP和多个module的解耦,还可以进一步优化吗?每个module都要实现往manager注册过程的代码,挺麻烦的。我们可以把这个注册管理的过程,使用注解来进行代替。

每个module只需添加annotation,编译生成api和module的对应关系,然后呢,optimus根据对应关系加载module。

这样APP只需依赖api和optimus就可以。

详细的processor如何生成对应关系和optimus如何根据接口加载实现类

也可以使用 ServiceLoader + @AutoService 实现

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface OptimusService {
    /** Returns the interfaces implemented by this service provider. */
    Class<?> value();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
@OptimusService(ABaseApi.class)
public class DemoImplA implements ABaseApi {
    private final String TAG = "DemoImpl";
    @Override
    public void init() {
        Log.d(TAG, "init DemoImplA");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意:如果用的是kotlin,将 annotationProcessor 改为 kapt,添加 plugins { id ‘kotlin-kapt’ }生成的optimus位置在 build/tmp/kapt3/classes

加载优化

到此annotation+processor+optimus是已支持各组件解耦,无论多少个不同的module和api,APP都只依赖api和optimus就可以。

那还能不能进一步再优化呢?比如加载提前初始化?初始化放在哪里合适呢?

为了不影响应用启动的速度,又能提前初始化,我们放在首页创建的时候吧。

通过ActivityLifecycleCallbacks监听activity的创建,反射调用垂直化SDK统一入口的初始化方法。

public class OptimusProvider extends ContentProvider {

    @Override
    public boolean onCreate() {
        Application application = Utils.getApplication();
        if (application != null) {
            application.registerActivityLifecycleCallbacks(new OptimusLifecycle());
        }
        return true;
    }
    ……
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
public class OptimusLifecycle implements Application.ActivityLifecycleCallbacks {

  private static final String TAG = "OptimusLifecycle";

  private final AtomicInteger createdCounter = new AtomicInteger();
  private final AtomicBoolean isChangingConfigurations = new AtomicBoolean(false);

  @Override
  public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
      if (createdCounter.getAndIncrement() == 0 && !isChangingConfigurations.getAndSet(activity.isChangingConfigurations())) {
          initOptimus(activity.getApplication());
      }
  }

  ……

  @Override
  public void onActivityDestroyed(@NonNull Activity activity) {
      createdCounter.getAndDecrement();
      isChangingConfigurations.set(activity.isChangingConfigurations());
  }

  private void initOptimus(Application application) {
      OptimusExecutor.getInstance().executorCallerRunsPolicy(() -> {
          // 反射调用垂直化SDK统一入口的初始化方法
          try {
              final Class<?> optimusSdkClass = Class.forName("com.ghp.optimus.OptimusSdk");
              final Field sdkInfos = optimusSdkClass.getDeclaredField("SDK_INFOS");
              sdkInfos.setAccessible(true);
              Class<?> initCallbackClass = Class.forName("com.ghp.optimus.InitCallback");
              Method init = optimusSdkClass.getMethod("init", Context.class, initCallbackClass);
              init.invoke(null, application, null);
          } catch (Throwable ignore) {
          }
      });
  }

}
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

可插拔

前面已经通过SPI机制实现了解耦,模块可插拔,那怎么让包大小也一起优化呢?

在Android里有fat-aar-android插件,该插件提供了将library以及它依赖的library一起打包成一个完整aar的解决方案。

可以根据配置文件,利用fat-arr将各个module自由选择的打包,这里不多介绍,可以查看 fat-aar-android的使用。

最终在Jenkins打包添加配置

……
type "%contains%"
call gradle engine:build -PCONTAIN="%contains%"
……
  • 1
  • 2
  • 3
  • 4

作者:九卿
链接:https://www.jianshu.com/p/c65a307223c9

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

一、架构师筑基必备技能

1、深入理解Java泛型
2、注解深入浅出
3、并发编程
4、数据传输与序列化
5、Java虚拟机原理
6、高效IO
……

在这里插入图片描述

二、Android百大框架源码解析

1.Retrofit 2.0源码解析
2.Okhttp3源码解析
3.ButterKnife源码解析
4.MPAndroidChart 源码解析
5.Glide源码解析
6.Leakcanary 源码解析
7.Universal-lmage-Loader源码解析
8.EventBus 3.0源码解析
9.zxing源码分析
10.Picasso源码解析
11.LottieAndroid使用详解及源码解析
12.Fresco 源码分析——图片加载流程

在这里插入图片描述

三、Android性能优化实战解析

  • 腾讯Bugly:对字符串匹配算法的一点理解
  • 爱奇艺:安卓APP崩溃捕获方案——xCrash
  • 字节跳动:深入理解Gradle框架之一:Plugin, Extension, buildSrc
  • 百度APP技术:Android H5首屏优化实践
  • 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
  • 携程:从智行 Android 项目看组件化架构实践
  • 网易新闻构建优化:如何让你的构建速度“势如闪电”?

在这里插入图片描述

四、高级kotlin强化实战

1、Kotlin入门教程
2、Kotlin 实战避坑指南
3、项目实战《Kotlin Jetpack 实战》

  • 从一个膜拜大神的 Demo 开始

  • Kotlin 写 Gradle 脚本是一种什么体验?

  • Kotlin 编程的三重境界

  • Kotlin 高阶函数

  • Kotlin 泛型

  • Kotlin 扩展

  • Kotlin 委托

  • 协程“不为人知”的调试技巧

  • 图解协程:suspend

在这里插入图片描述

五、Android高级UI开源框架进阶解密

1.SmartRefreshLayout的使用
2.Android之PullToRefresh控件源码解析
3.Android-PullToRefresh下拉刷新库基本用法
4.LoadSir-高效易用的加载反馈页管理框架
5.Android通用LoadingView加载框架详解
6.MPAndroidChart实现LineChart(折线图)
7.hellocharts-android使用指南
8.SmartTable使用指南
9.开源项目android-uitableview介绍
10.ExcelPanel 使用指南
11.Android开源项目SlidingMenu深切解析
12.MaterialDrawer使用指南
在这里插入图片描述

六、NDK模块开发

1、NDK 模块开发
2、JNI 模块
3、Native 开发工具
4、Linux 编程
5、底层图片处理
6、音视频开发
7、机器学习

在这里插入图片描述

七、Flutter技术进阶

1、Flutter跨平台开发概述
2、Windows中Flutter开发环境搭建
3、编写你的第一个Flutter APP
4、Flutter开发环境搭建和调试
5、Dart语法篇之基础语法(一)
6、Dart语法篇之集合的使用与源码解析(二)
7、Dart语法篇之集合操作符函数与源码分析(三)

在这里插入图片描述

八、微信小程序开发

1、小程序概述及入门
2、小程序UI开发
3、API操作
4、购物商场项目实战……

在这里插入图片描述

全套视频资料:

一、面试合集
在这里插入图片描述
二、源码解析合集

在这里插入图片描述
三、开源框架合集

在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

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

闽ICP备14008679号