带你走进组件化(三)—— 曲径

前言

上两篇文章我们初步掌握了组件化的使用和创建,今天就梳理一下组件化过程中出现的问题,模块之间如何通信,跨模块如何跳转传值等

资源冲突
1.Application冲突
我们都知道Application对于每一个运行的App来说都是必须的,即使你并未创建,App也会自主添加,这一小节就主要说Application的冲突问题。为了更好的说明情况,我在Module里和主App里都创建了一个Application,并在清单文件里添加
项目结构


    <application
        android:name=".MainApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.myfirstmodule">

    <application
        android:name=".application.BaseApplication"
        android:allowBackup="true"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MyFirstModuleMainActivity"
            android:screenOrientation="portrait" />
    </application>

</manifest>

添加完成后,点击运行,将会报错,大意是Application冲突了,
Application冲突截图而且解决冲突的办法也已经提示出来了,只要在清单文件里加入tools:replace="android:name"就可以了,我们修改清单文件,然后点击运行
2.资源冲突
举个简单的例子来说明吧,在string加入一个测试字段(主APP和Module都加入,命名一致),然后在布局中引用
资源冲突测试
资源冲突测试2运行测试,通过程序我们看到如果资源文件字段名相同,将会统一取主APP内部的资源,而不是从自己内部资源文件拉取
资源冲突

3.引用版本冲突
引用版本冲突一般表现为引用第三方库因为版本不一致而导致冲突出现,就拿常用的RxJava来举个例子吧:
首先我们在Module里引用最新的RxJava库
RxJava最新版本然后在AppModule里引用其他版本的RxJava库,就以2.2.4为例
2.2.4版本RxJava编译
不出意外将会报错
WARNING: Conflict with dependency ‘io.reactivex.rxjava2:rxjava’ in project ‘:app’. Resolved versions for runtime classpath (2.2.5) and compile classpath (2.2.4) differ. This can lead to runtime crashes. To resolve this issue follow advice at https://developer.android.com/studio/build/gradle-tips#configure-project-wide-properties. Alternatively, you can try to fix the problem by adding this snippet to E:\Android Project\MyDemo\TestModule\app\build.gradle:
这就是不同版本引用报错
到这里会有很多人会说把版本号都提取出来,统一管理不就好了,是的,就是这样,我们将公共资源统一提取出来,然后统一引用,统一更改,这样就能保持各个Module版本一致,不会出现冲突

在是上两节我们曾将App的版本号等做了处理,统一归置global_config.gradle文件中,这里我们使用同样的方法,将各个库的版本统一放在这个文件中,然后统一调用

修改global_config.gradle,将RxJava写入

  /**
     * rxjava version
     */

    rxjavaVersion = "2.2.5"

    otherLibrary =
            [
                    rxjava : "io.reactivex.rxjava2:rxjava:$rxjavaVersion"
            ]

在主App和Module统一调用

implementation rootProject.ext.otherLibrary.rxjava

这里延展一下,我们都知道Android碎片化十分严重,而各个版本管理也十分混乱,而谷歌为了更好的解决这类问题推出了AndroidX,这里我们同样可以把引用文件修改一下,直接改成引用AndroidX库

global_config.gradle

ext {
    /**
     * 是否是调试模式
     */
    isDebug = false
    /**
     * 编译SDK版本
     */
    compileSdkVersion = 28

    /**
     * 最新支持版本
     */
    minSdkVersion = 15
    /**
     * 目标SDK版本
     */
    targetSdkVersion = 28
    /**
     * 版本号
     */
    versionCode = 1
    /**
     * 版本信息
     */
    versionName = "1.0"

    /**
     * rxjava version
     */

    rxjavaVersion = "2.2.5"

    /**
     * V7Library version
     */

    V7LibraryVersion = "1.0.0"
    /**
     * constraint-layout version
     */

    constraint_layoutVersion = "1.1.2"
    /**
     * junit version
     */

    junitVersion = "4.12"
    /**
     * runner verison
     */
    runnerVersion = "1.1.0"
    /**
     * espresso_core version
     */
    espresso_coreVersion = "3.1.0"
    otherLibrary =
            [
                    rxjava           : "io.reactivex.rxjava2:rxjava:$rxjavaVersion",
                    V7Library        : "androidx.appcompat:appcompat:$V7LibraryVersion",
                    constraint_layout: "androidx.constraintlayout:constraintlayout:$constraint_layoutVersion",
                    junit            : "junit:junit:$junitVersion",
                    runner           : "androidx.test:runner:$runnerVersion",
                    espresso_core    : "androidx.test.espresso:espresso-core:$espresso_coreVersion"
            ]

}

引用

    implementation rootProject.ext.otherLibrary.V7Library
    implementation rootProject.ext.otherLibrary.constraint_layout
    testImplementation rootProject.ext.otherLibrary.junit
    androidTestImplementation rootProject.ext.otherLibrary.runner
    androidTestImplementation rootProject.ext.otherLibrary.espresso_core
    implementation rootProject.ext.otherLibrary.rxjava

最后修改Activity和布局引用就可以了

跨模块之间跳转传值
在前面我们已经实现过跨组件跳转,但是这样耦合性太高了,没一个需要用到的Activity都需要在AndroidManifest.xml中注册,如果没有注册将会报错,甚至崩溃,这样的耦合性是我们无法忍受的,因为我们将项目组件化就是一个解耦的过程,这时我们就需要一个路由控制的框架——ARouter

ARouter是阿里开源的一套 用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦

ARouter描述

按照相同的套路,我们先集成,然后使用
但是这里有两个个问题,第一个问题是因为AndroidX的问题,因为我们这里使用了AndroidX,而ARouter对AndroidX支持的不太友好,所以我们在使用AndroidX的情况下使用ARouter需要更改点东西,首先我们要gradle.properties增加两句代码

android.useAndroidX=true
android.enableJetifier=true

第二个问题是因为V4包冲突的问题,所以我们在集成里过滤一下,例如

  implementation (rootProject.ext.otherLibrary.arouter_api) {
        exclude group: 'com.android.support'
    }
    annotationProcessor (rootProject.ext.otherLibrary.arouter_compiler) {
        exclude group: 'com.android.support'
    }

集成后使用也很简单
先是添加注解,这里需要注意,路由路径最少是两层
ARouter添加注解

然后初始化,尽可能要早点哦,不然就会影响跳转操作了,所以我这里直接放在了Application中的onCreate方法内部了

   if (true) {          
            ARouter.openLog();     
            ARouter.openDebug();   
        }
 ARouter.init(this);

最后发起跳转

ARouter.getInstance().build("/baseModule/firstActivity").navigation();

至于如何传值跳转,如何拦截,具体功能还需要自己去看文档,这里我就不一一赘述了——ARouter

模块之间通信
跳转知道了我们就该说说如何通信了,其实通信方式有很多种,例如广播,但是使用广播又会出现了耦合性的问题,所以我们这里并不太建议使用广播,而最常用的也有EventBus,RxBus等,EventBus我在以前的文章中已经说过了,这里就不在说EventBus了,我们主要说下RxBus,可能细心的朋友们已经留心了我在前面集成了RxJava,而RxBus就是RxJava一种使用方式,在这里我就不集成RxBus库了,只写一个简单用法,告诉大家如何使用,至于优化封装就要靠自己了

首先我先创建了一个RxBus类,类内部有两个方法,一个post方法,一个receive方法,用于发送数据和接收数据,逻辑也不复杂,就是从post里发送,然后receive里接收,具体代码如下

public class RxBus {

    public Observable<String> observable;

    private static RxBus rxBus;
    String message;
    public static RxBus getRxBus() {
        if (rxBus == null) {
            rxBus = new RxBus();
        }
        return rxBus;
    }

    public void post(String string) {
        observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext(string);
                emitter.onComplete();
            }
        });
    }

    public String receive() {
            observable.subscribe(new Observer<String>() {
                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(String s) {
                    message=s;
                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {

                }
            });
        return message;
    }

}

然后在主APP里向Module里发送数据测试,

 RxBus rxBus=RxBus.getRxBus();
 rxBus.post("我是测试发送数据");

在Module里接收显示

RxBus rxBu = RxBus.getRxBus();
test.setText(rxBu.receive());

RxJava发送数据测试

总结

在组件化过程中会遇到很多问题,在写这篇文章之前我已经写过一个简单示例了,但是再一次写的时候还是有很多问题是我没有预料到的,也出现了不少莫名的bug,比较麻烦的bug或者常见的一些错误我都在文章中提到了,也说了解决办法,或许大家在写的时候还会出现一些跟我不一样的错误,但是不要恐惧,根据错误提示,一点一点找原因,总有解决办法,这本身就是一个学习的过程。

愿与君共勉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值