美文网首页
Android组件化

Android组件化

作者: Coder_Sven | 来源:发表于2020-06-08 22:06 被阅读0次

    模块化:根据不同的关注点,将一个项目的可以共享的部分抽取出来,形成独立的Module,这就是模块化。模块化不只包含公共部分,当然也可以是业务模块。比如:图片加载模块

    组件化:组件化是建立在模块化思想上的一次演进,一个变种。组件化本来就是模块化的概念。核心是模块角色的可转化换性,在打包时,是library;调试时,时application。组件化的单位是组件

    插件化:严格意义来讲,其实也算是模块化的观念。将一个完整的工程,按业务划分为不同的插件,来化整为零,相互配合。插件化的单位是apk(一个完成的应用)。可以实现apk 的动态加载,动态更新,比组件化更灵活。

    Gradle组件化配置

    build.gradle // 构建脚本文件,主要的构建配置都在这里写
    gradle // 存放gradle wrapper 执行配置和工具的文件夹,
    gradlew // gradle wrapper 执行脚本文件,用来在没有安装 gradle 的情况下执行 gradle 命令。当然,第一次执行时会下载 gradle。
    gradlew.bat // gradle wrapper 执行脚本文件的 windows 版
    settings.gradle // 项目配置,指明根项目名字和引入的 module

    我们创建两个AndroidLibrary的Module分别是module1和module2

    image-20200530095416112.png

    在项目的build.gradle中引入一个gradle配置文件

    apply from:"config.gradle"
    

    config.gradle

    ext{
        // false: 组件模式
        // true :集成模式
        isModule = true
        android = [
                compileSdkVersion:28,
                minSdkVersion:15,
                targetSdkVersion:28,
                versionCode:1,
                versionName:"1.0"
        ]
    
        appId = [
                "app":"com.highgreat.sven.component",
                "module1":"com.highgreat.sven.module1",
                "module2":"com.highgreat.sven.module2"
        ]
    
        supportLibrary = "28.0.0"
        dependencies = [
                "appcompat-v7a" : "com.android.support:appcompat-v7:${supportLibrary}",
        ]
    }
    

    在整个项目的build.gradle引入这些配置之后,其他所有的modulde都可以统一使用项目的这些配置,用来统一版本

    然后在app的build.gradle中进行配置

    apply plugin: 'com.android.application'
    
    //赋值与引用  这样好用来统一管理版本
    def cfg = rootProject.ext.android
    def appId = rootProject.ext.appId
    
    android {
        compileSdkVersion cfg.compileSdkVersion
        defaultConfig {
            applicationId appId["app"]
            minSdkVersion cfg.minSdkVersion
            targetSdkVersion cfg.targetSdkVersion
            versionCode cfg.versionCode
            versionName cfg.versionName
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation 'com.android.support:appcompat-v7:28.0.0'
        implementation 'com.android.support.constraint:constraint-layout:1.1.3'
        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'
    
        if (isModule){
            implementation project(':module2')
            implementation project(':module1')
        }
    }
    

    这样配置之后,主项目app就可以跳转到module1和module2中。这样就可以团队合作,一个人完成app模块的功能,其他人分别完成moduel1或者module2,但是目前这种情况还有两个问题。

    问题1,module没法独立运行,编写module的开发人员没办法独立运行module代码进行测试。

    问题2,上面只实现了app能够跳转到moduel1或者moduel2,那么module1要跳转到module2又该怎么实现呢?

    解决问题1:在module2中配置

    //根据isModule标签动态的切换 集成/组件模式  
    if (isModule){
        apply plugin: 'com.android.library'
    }else{
        apply plugin: 'com.android.application'
    }
    
    def cfg = rootProject.ext.android
    def appId = rootProject.ext.appId
    
    android {
        compileSdkVersion cfg.compileSdkVersion
    
    
        defaultConfig {
            minSdkVersion cfg.minSdkVersion
            targetSdkVersion cfg.targetSdkVersion
            versionCode cfg.versionCode
            versionName cfg.versionName
    
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = [ moduleName : project.getName() ]
                }
            }
    
            //添加一条 boolean类型的变量
            buildConfigField("boolean","isModule",String.valueOf(isModule))
    
            //组件模式下
            if (!isModule){
                applicationId appId['module2']
            }
    
            //资源配置
            sourceSets{
                main{
                    //在组件模式下 使用不同的manifest文件
                    if(!isModule){
                        manifest.srcFile 'src/main/module/AndroidManifest.xml'
                        java.srcDirs 'src/main/module/java','src/main/java'
                    }else{
                        manifest.srcFile 'src/main/AndroidManifest.xml'
                    }
                }
            }
    
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    
    }
    
    dependencies {
        implementation 'com.android.support:appcompat-v7:28.0.0'
        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'
    }
    

    这样一来通过修改项目中的isModule参数来让module2可以变成application来独立运行,这样编写module代码的开发人员就只需要负责单独的这个module模块就好了。

    解决问题2:因为module1和module2没有互相引用对方,所以startActivity是没办法实现的。这时就需要类似ARouter等的路由跳转框架来实现了。

    ARouter路由原理:

    路由原理.png

    核心思想如上面的图示,我们在代码里加入的@Route注解,会在编译时期通过apt生成一些存储path和activity.class映射关系的类文件,然后app进程启动的时候会加载这些类文件,把保存这些映射关系的数据读到内存里(保存在map里),然后在进行路由跳转的时候,通过build()方法传入要到达页面的路由地址,ARouter会通过它自己存储的路由表找到路由地址对应的Activity.class(activity.class = map.get(path)),然后new Intent(context, activity.Class),当调用ARouter的withString()方法它的内部会调用intent.putExtra(String name, String value),调用navigation()方法,它的内部会调用startActivity(intent)进行跳转,这样便可以实现两个相互没有依赖的module顺利的启动对方的Activity了。

    手写实现ARouter

    项目结构

    image-20200530113419637.png

    1,创建一个JavaLibrary module router-annotation

    image-20200530135216120.png

    在这个module下主要是自定义注解类@Route,@Extra

    2,创建一个router-compiler的Java-Library module,并且引用router-annotation

    image-20200530144456836.png

    build.gradle

    apply plugin: 'java-library'
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    
        annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
        compileOnly 'com.google.auto.service:auto-service:1.0-rc4'
    
        implementation 'com.squareup:javapoet:1.11.1'
        implementation project(':router_annotation')
    
    }
    
    // java控制台输出中文乱码
    tasks.withType(JavaCompile) {
        options.encoding = "UTF-8"
    }
    
    sourceCompatibility = "7"
    targetCompatibility = "7"
    

    这个module是我们自定义的注解处理器。Annotation Processor是javac的一个工具,它用来在编译时扫描和处理注解。通过Annotation Processor可以获取到注解和被注解对象的相关信息,然后根据注解通过javapoet自动生成Java代码,省去了手动编写,提高了编码效率。


    image-20200530145212839.png

    javapoet:自动生成java代码

    比如给点一个class文件

    package com.example.helloworld;
    
    public final class HelloWorld {
      public static void main(String[] args) {
        System.out.println("Hello, JavaPoet!");
      }
    }
    

    使用javapoet生成一个相同的class文件

    //生成main函数
    MethodSpec main = MethodSpec.methodBuilder("main")
        .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
        .returns(void.class)
        .addParameter(String[].class, "args")
        .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
        .build();
    
    //生成HelloWorld类
    TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
        .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
        .addMethod(main)
        .build();
    
    JavaFile javaFile = JavaFile.builder("com.example.helloworld", helloWorld)
        .build();
    
    javaFile.writeTo(System.out);
    

    3,创建一个router-core的AndroidLibrary module,并且引用router-annotation

    image-20200530140053318.png

    这个module是核心module,主要作用是进行路由的分组,页面跳转的具体实现

    build.gradle

    apply plugin: 'com.android.library'
    
    android {
        compileSdkVersion 28
    
        defaultConfig {
            minSdkVersion 15
            targetSdkVersion 28
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
    
    }
    
    dependencies {
        implementation fileTree(dir: 'libs', include: ['*.jar'])
    
        implementation 'com.android.support:appcompat-v7:28.0.0'
        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'
    
        // compile被废弃
        // api:同compile
        // implementation: 不会进行传递依赖
        // 即router-annotation模块只对 本模块(router-core) 开放,
        // 无法在 app 模块中使用
        api project(':router_annotation')
    }
    

    分析一下大致的逻辑:

    通过自定义注解,找到要跳转的页面的全路劲名称(比如:com.highgreat.sven.module1.Module1Activity),然后通过ActivityCompat.startActivity(context,intent,Bundle)来实现跳转页面的目的。

    具体的请看项目代码

    https://github.com/games2sven/Component

    相关文章

      网友评论

          本文标题:Android组件化

          本文链接:https://www.haomeiwen.com/subject/qkshzhtx.html