Android组件化通信方案

Android组件化通信方案

一、背景

随着业务规模不断扩大,模块化和组件化必将是一个很大的趋势。组件化的基础就是模块化,不断将业务进行拆分,按照业务边界将其拆分成一个个独立可测试、可运行的模块。但是必须面临一个很大问题就是组件与组件之间的通信问题。关于组件之间通信问题,业界主要有两种方式: 第一种是基于自定义URL索引协议路由规则; 第二种则是基于接口实现的规则, 面向接口编程,只依赖组件的接口不依赖实现。

二、遇到的问题

URL索引规则比较灵活,将会面临一个问题就是URL索引维护成本,并且URL索引会散落在各个页面中。尽管集中式管理,但是随着业务模块的增加URL表会不断增加。基于这一点还是选择第二种方式基于接口实现的方式。

不管是基于哪种方式,还有一个问题需要解决就是URL索引存放位置或者组件接口存在位置问题,大部分一般放在base中下沉到底层。但是很明显这样做是有问题的,随着业务模块增加,下沉的底层内容将会不断膨胀。每增加一个模块base就得修改一次。于是我们需要解决一个问题就是将注册接口水平化,于是就有了Quark组件化通信框架.

然后如果是基于接口实现规则通信,还会遇到一个问题那就是组件之间循环引用的问题,quark框架提供一个解决思路那就是为对应的组件配置一个SDK组件模块。不再互相引用组件了,而是引用各自的SDK组件模块.

三、框架思想

框架的基本思想就是基于接口实现的规则,每个组件都有一个与之对应的SDK组件,组件间通信只要通过依赖对方的SDK接口进行通信即可,对于公用的Model, 各个调用方需要自己内部做转换。组件只需要在Application启动的时候注册组件挂载点即可,每个组件的挂载点可以搭载多个服务,调用方只需要拿到对应组件的挂载点,并且在挂载点中取出对应的服务调用即可。

Service服务接口都存在于SDK模块中,然后实现组件模块中有对应的实现,然而Quark以一个独立的lib稳定下沉到下层,下次如果需要增加新的模块只需要实现对应的SDK,在Application中注册挂载点即可,从而解决了下沉问题。SDK之间不能互相引用,SDK按道理不需要依赖什么。然后SDK和组件模块以独立的版本号管理。

四、框架使用步骤

  • 1、创建组件模块声明SDK,我们假设这个sdk项目叫 module-login-sdk. 并在内部声明一个LoginApi服务。
package com.shanbay.quark.module_login_sdk;

public interface LoginApi {
    String login(String username, String password);
}

注意: sdk项目不会依赖其他任何东西,也就是说对于build.gradle需要非常的干净

apply plugin: 'com.android.library'

android {
    compileSdkVersion 27
    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:27.1.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
  • 2、创建组件实现模块,我们假设这个项目叫 module-login.,在module-login的模块中依赖module-sdk和quark_lib库
apply plugin: 'com.android.library'
android {
    compileSdkVersion 27
    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation project(":module-payment-sdk")
    implementation project(":bay-lib-quark")
    implementation project(":module-login-sdk")
}
  • 3、然后实现sdk中服务Service的内容,具体Service实现
public class LoginApiImpl implements LoginApi {
    @Override
    public String login(String username, String password) {
        QuarkService quarkService = QuarkService.getInstance();
        PaymentApi paymentApi = quarkService.get(PaymentApi.class);
        return paymentApi != null ? paymentApi.pay(10) : "null";
    }
}
  • 4、同时你需要提供一个register来帮助module把自己的服务挂载出去
public class LoginServiceRegister implements IQuarkServiceRegistry {
    @Override
    public void registerService(@NonNull IQuarkService service) {
        if (service != null) {
            service.put(LoginApi.class, new LoginApiImpl());
        }
    }
}
  • 5、使用quark,在App测试壳子中依赖组件、组件SDK以及quark-lib
apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.shanbay.quark.shanbay_lib_quark"
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation project(":module-login")
    implementation project(":module-payment")
    implementation project(":module-login-sdk")
    implementation project(":module-payment-sdk")
    implementation project(":bay-lib-quark")
}
  • 6、然后在APP的Application中注册挂载点
public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();

        QuarkService service = QuarkService.getInstance();//全局唯一单例,服务集合管理者

        LoginServiceRegister loginServiceRegister = new LoginServiceRegister();//创建Login模块服务的挂载点
        loginServiceRegister.registerService(service);//Login挂载点注册所要携带的服务集合,传入服务管理者,实际上是把login中的服务集合通过服务管理者进行注册和管理。

        PaymentServiceRegister paymentServiceRegister = new PaymentServiceRegister();
        paymentServiceRegister.registerService(service);
    }
}
  • 7、利用Quark调用对应的Service
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

        LoginApi loginApi = QuarkService.getInstance().get(LoginApi.class);
        Toast.makeText(this, loginApi.login("fuck", "fuck"), Toast.LENGTH_SHORT).show();
    }
}

五、框架源码解析

  • 1、服务Service抽象管理者接口,定义了服务Service管理者具有的行为
public interface IQuarkService {
    <T> void put(@NonNull Class<T> clazz, @NonNull T o);
    <T> T get(@NonNull Class<T> clazz);
}
  • 2、服务Service管理者的实现,主要把挂载点中的服务以Class为key,Service实例为value形式存储起来。并且提供服务获取。
public class QuarkService implements IQuarkService {
    private static QuarkService sService;
    private final Map<Class<?>, Object> mInstanceMap = new ConcurrentHashMap<>();
    private QuarkService() {}
    public static QuarkService getInstance() {
        if (sService == null) {
            synchronized (QuarkService.class) {
                if (sService == null) {
                    sService = new QuarkService();
                }
            }
        }
        return sService;
    }

    @Override
    public <T> void put(@NonNull Class<T> clazz, @NonNull T o) {
        if (clazz != null) {
            mInstanceMap.put(clazz, o);
        }
    }

    @Override
    public <T> T get(Class<T> clazz) {
        if (clazz == null) {
            return null;
        }

        Object o = mInstanceMap.get(clazz);
        return (T) o;
    }
}
  • 3、服务的挂载点抽象接口,由各个模块实现中的服务的挂载点去实现,并在并实现内容中把实际上的服务注册进去。
public interface IQuarkServiceRegistry {
    void registerService(@NonNull IQuarkService service);
}
  • 4、在具体的模块中去实现具体模块服务挂载点
public class LoginServiceRegister implements IQuarkServiceRegistry {
    @Override
    public void registerService(@NonNull IQuarkService service) {
        if (service != null) {
            service.put(LoginApi.class, new LoginApiImpl());
        }
    }
}

   转载规则


《Android组件化通信方案》 mikyou 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
基于用户行为事件开发自测模式思考 基于用户行为事件开发自测模式思考
基于用户行为事件开发自测模式思考一、简述 在开发过程中,每个开发者必须保证代码质量。保证开发代码质量实际上在开发阶段各个环节,主要包括三个环节: 开发前方案流程设计和预研、开发中代码质量、开发完毕后代码自测。以上三个环节都很重要,或者漏了上
2019-12-23
下一篇 
Android-H5首屏秒开优化方案 Android-H5首屏秒开优化方案
Android-H5首屏秒开优化方案一、遇到的问题 在实现阅读APP从原生渲染迁移到webview渲染过程中,发现WebView第一加载会出现白屏,但是后续打开WebView速度就会明显快很多。 二、具体实现方案 首先,通过客户端去请求A
2019-12-22