Android项目组件化实践

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/z979451341/article/details/80929805

本博客使用的示例项目都来自以下地址

https://github.com/979451341/MDemo

一.组件化的概念和作用

      因为随着业务需求的增加,app的项目的体积不断变大,开发人员的工作量也会增加,所以后来会有更多的人负责开发app,需要协同工作,组件化和插件化就产生了。

      组件化的概念就是将一个项目分成多个组件进行完成,各个组件能够单独编译和运行,而又可以组合成一个完成的项目编译和运行。组件化使得多人同时编写一个项目更加方便,比如你编译一个组件就比编译一个完整的项目更加快捷,而且这样开发者之间只需要确定界面的跳转逻辑和服务调用关系、数据的传递就可以自由的编写代码而不用顾忌别人了。

    组件化的难点就是组件的之间解耦和动态的分割和组合。


二.如何组件化

1.确定module之间的关系

要完成组件化需要很多的步骤,首先我们要确定我们要创建哪些module,这些module有哪些关联

我这里就用我的示例项目来说说

app是主module,也就是宿主组件,就只用放置预览界面之类,不完成具体业务

firstmodule、second_module都是一些完成某种业务的组件,项目基本就是由这些module完成

mylibrary就是基础module,放置一些依赖、工具类、基础类,其他module都需要依赖它



2.各个组件的全局配置

我是首先在项目根目录创建了一个config.gradle,用来配置各个module

/*全局配置信息及第三方依赖统一管理*/
ext{
    isModule = false
    moduleFirst = false
    moduleSecond = false


    android = [
            compileSdkVersion   : 27,
            minSdkVersion       : 19,
            targetSdkVersion    : 27,
            versionCode         : 1,
            versionName         : "1.0.0",

            androidSupportSdkVersion: "27.1.1"
            
    ]

}
这个gradle需要导入根项目的build.gradle
apply from: "config.gradle"


3.组件的分割和组合

而各个module的分割和组合是由三个类似boolean变量完成的

isModule//如果为false,则将各个组件组合起来,否则就分割来开
moduleFirst//为false则是作为组件存在,如果为true则为单独的项目存在,但是需要isModule也为true才能正常运行
moduleSecond//和moduleFirst类似
我们再来看看各个module,是如何根据这个三个变量完成分割和组合的

比如firstmodule的build.gradle的头部,表示如果moduleFirst为true,则当前module是一个单独的项目,否则为一个library

if (Boolean.valueOf(rootProject.ext.moduleFirst)) {
    apply plugin: 'com.android.application'
} else {
    apply plugin: 'com.android.library'
}

还有没有完,我们还需要在AndroidManifest文件的加载上做功夫,如果moduleFirst为true,则加载module文件夹下AndroidManifest文件,否则加载默认目录的文件。

    /*java插件引入了一个概念叫做SourceSets,通过修改SourceSets中的属性,可以指定哪些源文件
(或文件夹下的源文件)要被编译,哪些源文件要被排除。*/
    sourceSets {
        main {
            if (rootProject.ext.moduleFirst) {
                manifest.srcFile 'src/main/module/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                java {
                    //排除java/debug文件夹下的所有文件
                    exclude '*module'
                }
            }
        }
    }

而这两个AndroidManifest文件最主要的区别是,有无自定义的Application类配置,和默认启动activity的配置,代码太多,就贴存在区别的一部分,也就是module文件夹下AndroidManifest的区别,具体的看项目源码

        <activity android:name=".FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        android:name="com.example.mylibrary.BaseApplication"

当你都把各个module配置好了,当config.gradle里那三个boolean变量为false,

    isModule = false
    moduleFirst = false
    moduleSecond = false

你运行app组件在手机上,这个时候是一个完整的项目


如果为如下,你可以运行firstmodule作为一个独立的app在手机上,second_module也是这样

    isModule = true
    moduleFirst = true
    moduleSecond = false


4.组件之间的跳转

ARouter框架非常强大,他能够帮助组件化时页面解耦的问题,因为你不需要知道你要跳转哪个activity,只需要知道路径就可以了,就算路径对应的activity不存在,那也不会报空指针错误。

关于ARouter在各个组件上的配置,需要注意一下,我们在mylibrary基础组件里配置了ARouter的相关配置

    //路由
    api 'com.alibaba:arouter-api:1.2.4'
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
    api 'com.alibaba:arouter-annotation:1.0.4'
虽然其他业务组件引入了mylibrary基础组件,但是还需要添加一行配置
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'

并且在defaultConfig也需要添加配置

        //Arouter路由配置
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [moduleName: project.getName()]
            }
        }

现在说说如何实现跳转,我在firstmodule的FirstActivity配置path

@Route(path = RouterURLS.FIRST_MAIN)
public class FirstActivity extends AppCompatActivity 

我在app主组件里就可以进行路由跳转

                //发起路由跳转
                ARouter.getInstance().build(RouterURLS.FIRST_MAIN).navigation(MainActivity.this);


5.组件之间传递数据

这个同样也是通过ARouter完成,比如你进行路由跳转的时候,你携带数据过去

        ARouter.getInstance().build(RouterURLS.SECOND_MAIN).withString("data","来自firstmodule FirstActivity的消息").navigation();

然后通过intent接受

        //接收参数
        Intent intent = getIntent();
        String data = intent.getStringExtra("data");
还有其他具体的传递数据的方式,你们就在ARouter框架官网看看

https://github.com/alibaba/ARouter


6.组件之间进行服务调用

还是通过ARouter实现

我在mylibrary定义一个接口,并继承IProvider,添加一个接口函数

public interface TestService extends IProvider {
    public void showToast(Context context);
}

然后在app主组件里实现这个接口,并配置path

@Route(path = RouterURLS.BASE_MYSERVICE, name="宿主的服务")
public class MainService implements TestService {

    @Override
    public void showToast(Context context) {
        Toast.makeText(context,"成功调用宿主模块的服务",Toast.LENGTH_SHORT).show();
    }


    @Override
    public void init(Context context) {

    }
}

在second_module里添加配置,你要知道TestService具体的实现类,我们是不知道

    @Autowired(name = RouterURLS.BASE_MYSERVICE)
    TestService service;

然后在onCreate函数里

        ARouter.getInstance().inject(this);

调用

service.showToast(SecondMainActivity.this);


三.结束

我写的实例项目还是非常简单,主要说明如何进行组件之间动态的分割和组合、跳转、传递数据、调用服务,这些都有一个例子,具体的看代码,大家也可以下载代码运行一下

关于插件化,本人感觉这门学问很是高深,只是探究了一下,有兴趣的可以看看一下博客

https://blog.csdn.net/z979451341/article/details/79766135


四.参考文章

从零开始搭建Android组件化框架

https://www.jianshu.com/p/ba32488f9555

Android 路由框架ARouter最佳实践

https://blog.csdn.net/zhaoyanjun6/article/details/76165252



展开阅读全文

没有更多推荐了,返回首页