【Andriod】组件化架构之实现组件可插拔

阳光穿透心脏的1/2处 2021-09-24 11:32 424阅读 0赞

上一篇文章讲解了如何在云端配置项目的依赖:

【Android】自定义Gradle Plugin实现云端配置项目依赖

这篇文章讲解,当修改了项目的依赖(dependencies{…})代码,比如删除或者新增了SDK组件,如何保证项目正常编译运行不受影响,即实现组件可插拔。

例如,应用依赖了library1、library2、library3、…这些library都是可选的,即可以全都要,可以全不要或者只要其中一部分。现在通过本地gradle或者在云端插件的方式选择了应用需要依赖哪些library,如何达到不需要修改代码,即可感知到功能的变化。

新建Demo Project名为MavenRepoDemo,新增三个Library,分别为:

  • 1、commonlibrary
    基础library,用来动态加载library1和library2。
  • 2、library1
    可选的library
  • 3、library2
    可选的library

项目结构如下:
在这里插入图片描述
其中app module是用来展示功能的,通过插件依赖了commonlibrary,commonlibrary是基础library,library1和library2是可选的。

根目录中的aar_upload.gradle文件是用来上传library到maven仓库的脚本。

app module中build.gradle没有配置任何依赖:

  1. apply plugin: 'com.android.application'
  2. apply plugin: 'MyPlugin'
  3. android {
  4. compileSdkVersion 29
  5. buildToolsVersion "29.0.1"
  6. defaultConfig {
  7. applicationId "com.devnn.mavenrepodemo"
  8. minSdkVersion 15
  9. targetSdkVersion 29
  10. versionCode 1
  11. versionName "1.0"
  12. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  13. }
  14. buildTypes {
  15. release {
  16. minifyEnabled false
  17. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  18. }
  19. }
  20. }
  21. dependencies {
  22. //note: here is nothing
  23. }

依赖是通过云端来完成的,具体内容参阅文章开头的链接。

app module中的MainActivity代码如下:

  1. package com.devnn.mavenrepodemo;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.widget.TextView;
  5. import com.devnn.commonlibrary.ILibrary;
  6. import com.devnn.commonlibrary.LibraryLoader;
  7. public class MainActivity extends AppCompatActivity {
  8. private TextView tvMessage;
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_main);
  13. tvMessage = findViewById(R.id.main_text);
  14. ILibrary library1 = LibraryLoader.getLibrary1();
  15. ILibrary library2 = LibraryLoader.getLibrary2();
  16. if (library1 != null) {
  17. tvMessage.append("\n");
  18. tvMessage.append(library1.hello());
  19. }
  20. if (library2 != null) {
  21. tvMessage.append("\n");
  22. tvMessage.append(library2.hello());
  23. }
  24. }
  25. }

当两个library加载成功后,运行显示:
在这里插入图片描述
其中Hello,World!是tvMessage控件默认的文本内容。

可以看到加载library是通过LibraryLoader来完成的。没有找到library时getLibraryX()方法返回null。

接下来讲解具体实现。

在commonlibrary中建立LibraryLoader.java类,用来加载其它的library。代码如下:

  1. package com.devnn.commonlibrary;
  2. import android.content.Context;
  3. import java.lang.reflect.Constructor;
  4. import java.lang.reflect.InvocationTargetException;
  5. /** * create by nannan on 2020/6/23 */
  6. public class LibraryLoader {
  7. public static ILibrary getLibrary1() {
  8. ILibrary library = loadLibrary("com.devnn.library1.Library1");
  9. return library;
  10. }
  11. public static ILibrary getLibrary2() {
  12. ILibrary library = loadLibrary("com.devnn.library2.Library2");
  13. return library;
  14. }
  15. private static ILibrary loadLibrary(String path) {
  16. ILibrary library = null;
  17. try {
  18. Class mClass = Class.forName(path);
  19. Constructor constructor = mClass.getConstructor();
  20. library = (ILibrary) constructor.newInstance();
  21. } catch (ClassNotFoundException e) {
  22. e.printStackTrace();
  23. } catch (InstantiationException e) {
  24. e.printStackTrace();
  25. } catch (InvocationTargetException e) {
  26. e.printStackTrace();
  27. } catch (NoSuchMethodException e) {
  28. e.printStackTrace();
  29. } catch (IllegalAccessException e) {
  30. e.printStackTrace();
  31. }
  32. return library;
  33. }
  34. }

可以看到要加载的library存在与否并不影响应用编译和运行。

其实这里核心技术点就是动态加载class文件。

另外,新建ILbrary.java类,作为其它library共同的接口:

  1. package com.devnn.commonlibrary;
  2. /** * create by nannan on 2020/6/22 */
  3. public interface ILibrary {
  4. String hello();
  5. }

只是简单输出一段文本。

在library1 module中新建Library1.java类,实现ILibrary接口:

  1. package com.devnn.commonlibrary;
  2. package com.devnn.library1;
  3. import com.devnn.commonlibrary.ILibrary;
  4. /** * create by nannan on 2020/6/10 */
  5. public class Library1 implements ILibrary {
  6. public String hello() {
  7. return "hello,I am Library1";
  8. }
  9. }

在library2 module中新建Library2.java类,实现ILibrary接口:

  1. package com.devnn.library2;
  2. import com.devnn.commonlibrary.ILibrary;
  3. /** * create by nannan on 2020/6/10 */
  4. public class Library2 implements ILibrary {
  5. public String hello(){
  6. return "hello,I am Library2";
  7. }
  8. }

整个Demo代码就这么多。

当在云端修改了要依赖的library,重新编译运行即可感知到功能的变化。

Demo Project源码:
https://github.com/devnns/MavenRepoDemo/tree/feathure/load_library_dynamic

发表评论

表情:
评论列表 (有 0 条评论,424人围观)

还没有评论,来说两句吧...

相关阅读

    相关 实现配置的

    引言: 三天前我们小组内部发生了争吵,原因是设计MQ层时一方想用 Kafka 另一方想用 RocketMQ 。小组因为这事争论了一个多小时,甚至还列了一个表格来对比双方优劣

    相关 Vue父子组件传值

    一、前言 作为国内使用较多的前端框架——Vue,作为一名开发人员是必须要掌握的,小编作为一名后端人员。由于公司前端人员不足,也是学起来了Vue! 框架的精髓就在于,组件

    相关 Android开发

    项目发展到一定程度,就必须进行模块的拆分。模块化是一种指导理念,其核心思想就是分而治之、降低耦合。而在 Android 工程实践,目前有两种途径,一个是组件化,一个是插件化。