组件化(从0-1完整构建组件化)

285 阅读3分钟

一 组件化和模块化的切换

1.新建一个组件化的module image.png 2.新建文件config.gradle image.png 3.在文件中输入控制组件化和模块化的参数

ext {
    android = [
            is_application: true
    ]
}

4.在项目的build.gradle中声明

image.png

这样声明了就是告诉项目在我们程序加载的时候去加载我们的config

5.然后在module中根据开关配置一下

image.png 代码

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

点击sync now 就可以了

二 Gradle统一版本号 1.在config.gradle命名公共配置 image.png 代码块

ext {
    android = [
            compileSdkVersion:32,
            minSdkVersion: 21,
            targetSdkVersion:32,
            versionCode: 1,
            versionName: "1.0",
            is_application: true
    ]
}

2 然后在module中修改 image.png

代码块

android {
    compileSdk rootProject.ext.android.compileSdkVersion

    defaultConfig {
        if (rootProject.ext.android.is_application) {
            applicationId "com.example.merber"
        }
        minSdk rootProject.ext.android.minSdkVersion
        targetSdk rootProject.ext.android.targetSdkVersion
        versionCode rootProject.ext.android.versionCode
        versionName rootProject.ext.android.versionName

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }


    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

三 AndroidManifest.xml文件的区分

因为application和library的AndroidManifest.xml文件是不同的,这个时候我们就需要区分了

我们再module模块中,添加一个manifest文件夹,并拷贝一份manifest文件进去

然后library的manifest文件是不需要intent的,这个时候就需要我们去掉intent以及Application里面的部分代码

image.png

image.png 代码

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.merber">

</manifest>

image.png 代码

sourceSets{
    main {
        if (rootProject.ext.android.is_application) {
            manifest.srcFile 'src/main/AndroidManifest.xml'
        } else {
            manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
        }
    }
}

四 library模块中不能有applicationId

image.png 这个异常是因为什么呢? 是因为我们的defaultConfig中设置了applicationId,但是library中是不需要的 怎么解决这个异常呢? 我们在设置applicationId的时候添加判断即可

image.png

五 组件之间的关联 1.建立annotation模块再建立文件

image.png

image.png

代码块

package com.example.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//编译时技术
@Target(ElementType.TYPE)   //声明注解的作用域  放在什么上面
@Retention(RetentionPolicy.CLASS)   //源码期  <  编译期  <  运行期 决定了注解的存在周期
public @interface BindPath {
    //key
    String value();
}

2 其他组件都引用annotation

image.png

image.png

image.png

3 需要调用的加 @BindPath("key/value") 这是将需要跳转的标记起来 下一步就是收集被标记的生成表格 apt技术

image.png 4.在每个组件中生成固定的包名 image.png 代码块

package com.example.router;

import com.example.arouter.ARouter;
import com.example.merber.MerberMainActivity;

public class MerberRouter {
    public  void putActivity(){
        ARouter.getInstance().addActivity("merber/MerberMainActivity", MerberMainActivity.class);
    }
}

5.建立总表new mode (arouter) image.png image.png

代码块

package com.example.arouter;

import android.app.Activity;
import android.content.Context;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ARouter {
    //有一个容器  装载了所有模块中的Activity的类对象 路由表
    private Map<String,Class<? extends Activity>> map;

    private static ARouter aRouter = new ARouter();
    private ARouter(){
        map = new HashMap<>();
    }


    public static ARouter getInstance(){
        return aRouter;
    }

    public void addActivity(String key,Class<? extends Activity> clazz){
        if(key!=null && clazz!=null && !map.containsKey(key)){
            map.put(key,clazz);
        }
    }
    //上下文
    private Context context;
    
}

建立接口

image.png

这样就完成了简单的模块化的东西了 但是使用还是不够方便 下面优化一下 让程序自己生成表

6 建立new mode(annotation_compiler)并添加注解处理器AnnotationCompiler

image.png 代码

import com.example.annotation.BindPath;
import com.google.auto.service.AutoService;

import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

//javac  就知道你
@AutoService(Processor.class)
public class AnnotationCompiler extends AbstractProcessor {

//    准备工作

    //生成代码的工具
    Filer filer;
    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filer = processingEnv.getFiler();
    }
//    处理什么组件


    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new HashSet<>();
        types.add(BindPath.class.getCanonicalName());
        return types;
    }
//jdk版本
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return processingEnv.getSourceVersion();
    }


    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//           1         elemtn
//        MerberActivity   PersonActivity 是   elements
        Set<? extends Element> elements =roundEnvironment.getElementsAnnotatedWith(BindPath.class);
//        零部件      MerberActivity  长城汽车 的   所有零部件    PersonActivity 比亚迪 的   所有零部件
        Map<String,String> map = new HashMap<>();
        for (Element element : elements) {
//写文件
            TypeElement typeElement = (TypeElement) element;
            String activityName = typeElement.getQualifiedName().toString();
//            key    meber/PersonActivity.class
            String key = typeElement.getAnnotation(BindPath.class).value();
            map.put(key,activityName+".class");
        }
        if(map.size() >0){
//写文件
            //生成工具类  然后写代码
            //工具类的类名
            String className = "ActivityUtil"+System.currentTimeMillis();
            Writer writer = null;
            try {

                writer= filer.createSourceFile("com.example.util." + className).openWriter();
                StringBuffer stringBuffer = new StringBuffer();
                stringBuffer.append("package com.example.util;\n");

                stringBuffer.append("import com.example.arouter.ARouter;\n");
                stringBuffer.append("import com.example.arouter.IRouter;\n");
                stringBuffer.append("public class " + className + " implements IRouter {\n");
                stringBuffer.append("@Override\n");
                stringBuffer.append("public void putActivity() {\n");
                Iterator<String> iterator = map.keySet().iterator();
                while (iterator.hasNext()){
                    String key = iterator.next();
                    String activityName = map.get(key);
                    stringBuffer.append("ARouter.getInstance().addActivity(""+key+"","+activityName+");");

                }
                stringBuffer.append("\n}\n}");
                writer.write(stringBuffer.toString());

            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(writer!=null){
                    try {
                        writer.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return false;
    }
}

在builder中修改如下

plugins {
    id 'java-library'
}


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    //3.4+<
    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc4'
    compileOnly 'com.google.auto.service:auto-service:1.0-rc3'

    //3.4-
//    implementation 'com.google.auto.service:auto-service:1.0-rc1'
    implementation project(path: ':annotation')
}

sourceCompatibility = "7"
targetCompatibility = "7"

组件依赖annotation_compiler 7.在组件的builder中修改

image.png

annotationProcessor project(path: ':annotation_compiler')

编译后会产生路由文件

image.png 8 我们做了组件的收集 现在要做到被调用(apt) 修改arouter

package com.example.arouter;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import dalvik.system.DexFile;

public class ARouter {
    //有一个容器  装载了所有模块中的Activity的类对象 路由表
    private Map<String,Class<? extends Activity>> map;

    private static ARouter aRouter = new ARouter();
    private ARouter(){
        map = new HashMap<>();
    }


    public static ARouter getInstance(){
        return aRouter;
    }

    public void addActivity(String key,Class<? extends Activity> clazz){
        if(key!=null && clazz!=null && !map.containsKey(key)){
            map.put(key,clazz);
        }
    }
    //上下文
    private Context context;


    public void init(Context context){

        this.context = context;
//     com.example.util
        //执行生成的工具类中的方法  将Activity的类对象加入到路由表中
        List<String> classNames = getClassName("com.example.util");
        for (String className : classNames) {
            try {
                Class<?> utilClass = Class.forName(className);
                if(IRouter.class.isAssignableFrom(utilClass)){
                    IRouter iRouter = (IRouter) utilClass.newInstance();
                    iRouter.putActivity();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }


        }
    }
    public void jumpActivity(String key, Bundle bundle){
        Class<? extends Activity> aClass = map.get(key);

        if(aClass == null){
            return;
        }
        Intent intent = new Intent(context,aClass);
        if(bundle!=null){
            intent.putExtras(bundle);
        }
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }
    /**
     * 通过包名获取这个包下面的所有的类名
     * @param packageName
     * @return
     */
    private List<String> getClassName(String packageName) {
        //创建一个class对象的集合
        List<String> classList = new ArrayList<>();
        try {
            //把当前应有的apk存储路径给dexFile
            DexFile df = new DexFile(context.getPackageCodePath());
//            不会发生类加载  性能    5000次  性能
            Enumeration<String> entries = df.entries();
            while (entries.hasMoreElements()) {
                String className = (String) entries.nextElement();
                if (className.contains(packageName)) {
                    classList.add(className);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classList;
    }

}

在app中建立新的文件BaseApplication

image.png

代码

import android.app.Application;

import com.example.arouter.ARouter;


public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ARouter.getInstance().init(this);
    }
}

在AndroidManifest中修改 image.png

android:name=".BaseApplication"

好了 组件化功能已经做完了,接下来在app调用merber 在app的mainActivity中调用

image.png

image.png

代码

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.example.arouter.ARouter;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        TextView textView = findViewById(R.id.button1);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ARouter.getInstance().jumpActivity("merber/MerberMainActivity",null);
            }
        });
    }

}

demo地址

gif_xahKs1gufh6jvr_8.gif