组件化开发和路由框架的理解

组件化以及实现

  • 组件化
    • 组件化的意义
    • 组件化的集成部署-Gradle配置
  • 路由
    • 组件化的子模块交互方式
    • 别人怎么处理问题
      • 路由的参数传递功能
      • 路由 组件本地图片、数据、其他方法通信 实现
      • Alibaba.Arouter分析

组件化

组件化的意义

  • 如果项目没有引入组件化:
    • 1.项目没有层次感,越来越大,无法管理
    • 2.代码重复太多而且高度耦合
    • 3.而且没办法单独开发,需要合并冲突;
  • 所以组件化的意义
    • 1.分层独立
    • 2.重复利用,高度解耦
    • 3.自由组装自由拆卸
  • 组件化和模块化的区别
    • 组件化为了复用而拆分,模块化为了业务分离而拆分;

组件化的集成部署-Gradle配置

  • a.包名和资源名冲突
  • b.版本号统一管理
  • c.组件和应用之间切换
  • d.清单文件区分

路由

组件化的子模块交互方式

思考集中方式实现:
方式一:使用EventBus,缺点:太多bean
方式二:使用广播 缺点:少用
方式三:隐式意图:缺点:配置太麻烦

<intent-filter>  
<action android:name="com.example.android.tst.SecondActivity"/>  
<category android:name="android.intent.category.DEFAULT" /> 
</intent-filter> 

Intent intent=new Intent("com.example.android.tst.SecondActivity"); 

方式四:使用类加载方式 缺点,写错报名类名

Class activityClass= Class.forName("");找到class字节码文件
new Intent(this,activityClass);

方式五:使用全局Map方式 类加载的封装自己去每个类都要在Application手动注册到map,难维护,一下几百行;

  • 问题: java反射机制中class.forName和classloader的区别
    • 1.class.forName()除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。当然还可以指定是否执行静态块
    • 2.classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。

别人怎么处理问题

原理:Arouter 像路由表注册分组和路径,向路由表查找并交互

生成两个类,一个类的HashMap,key为group,value为组下类;这个类HashMap,key为path,存放具体路径

预备点:java层级的工具,编译器干活,扫描全局注解

名称 作用
APT Annotation Processing Tool 根据规则,生成代码,类文件
JavaPoet 面向对象思维OOP: 先写方法放到类里面,再丢到包里面这样倒序的方式

ARouter 通过 Apt 技术,生成保存路径(路由 path)和被注解(@Router)的组件类的映 射关系的类,利用这些保存了映射关系的类,Arouter 根据用户的请求 postcard(明信片) 寻找到要跳转的目标地址(class),使用 Intent 跳转。

Group: key=="app" value="ARouter$$Path$$app" --------- /app/MainActivity

Path: key=="/app/MainActivity" value="MainActivity.class的封装类 RouterBean"

最终的效果:Group

public class ARouter$$Group$$personal implements ARouterGroup {
     
  @Override
  public Map<String, Class<? extends ARouterPath>> getGroupMap() {
     
    Map<String, Class<? extends ARouterPath>> groupMap = new HashMap<>();
    groupMap.put("personal", ARouter$$Path$$personal.class);
    return groupMap;
  }
}
最终的效果:Path

public class ARouter$$Path$$personal implements ARouterPath {
     
  @Override
  public Map<String, RouterBean> getPathMap() {
     
    Map<String, RouterBean> pathMap = new HashMap<>();
    pathMap.put("/personal/Personal_Main2Activity", RouterBean.create();
    pathMap.put("/personal/Personal_MainActivity", RouterBean.create());
    return pathMap;
  }
}

运行时注解反射处理
XUtil

编译器注解反射处理
EventBus -传统方式一行一行生成
Dagger2
Room
alibaba/Arouter - javapoet
ButterKnife - javapoet 优雅
DataBinding

// AutoService则是固定的写法,加个注解即可
// 通过auto-service中的@AutoService可以自动生成AutoService注解处理器,用来注册
// 用来生成 META-INF/services/javax.annotation.processing.Processor 文件
@AutoService(Processor.class)

// 允许/支持的注解类型,让注解处理器处理
@SupportedAnnotationTypes({
     ProcessorConfig.AROUTER_PACKAGE})

// 指定JDK编译版本
@SupportedSourceVersion(SourceVersion.RELEASE_7)

// 注解处理器接收的参数
@SupportedOptions({
     ProcessorConfig.OPTIONS, ProcessorConfig.APT_PACKAGE})

public class ARouterProcessor extends AbstractProcessor {
     

    // 操作Element的工具类(类,函数,属性,其实都是Element)
    private Elements elementTool;

    // type(类信息)的工具类,包含用于操作TypeMirror的工具方法
    private Types typeTool;

    // Message用来打印 日志相关信息
    private Messager messager;

    // 文件生成器, 类 资源 等,就是最终要生成的文件 是需要Filer来完成的
    private Filer filer;

    private String options;

    // 做初始化工作,就相当于 Activity中的 onCreate函数一样的作用
    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
     
        super.init(processingEnvironment);

        elementTool = processingEnvironment.getElementUtils();
        messager = processingEnvironment.getMessager();
        filer = processingEnvironment.getFiler();

        // 只有接受到 App壳 传递过来的书籍,才能证明我们的 APT环境搭建完成
        options = processingEnvironment.getOptions().get(ProcessorConfig.OPTIONS);
        String aptPackage = processingEnvironment.getOptions().get(ProcessorConfig.APT_PACKAGE);
        messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>>>>>>>>>> options:" + options);
        messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>>>>>>>>>> aptPackage:" + aptPackage);
        if (options != null && aptPackage != null) {
     
            messager.printMessage(Diagnostic.Kind.NOTE, "APT 环境搭建完成....");
        } else {
     
            messager.printMessage(Diagnostic.Kind.NOTE, "APT 环境有问题,请检查 options 与 aptPackage 为null...");
        }
    }

    /**
     * 相当于main函数,开始处理注解
     * 注解处理器的核心方法,处理具体的注解,生成Java文件
     *
     * @param set              使用了支持处理注解的节点集合
     * @param roundEnvironment 当前或是之前的运行环境,可以通过该对象查找的注解。
     * @return true 表示后续处理器不会再处理(已经处理完成)
     */
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
     
        if (set.isEmpty()) {
     
            messager.printMessage(Diagnostic.Kind.NOTE, "并没有发现 被@ARouter注解的地方呀");
            return false;
        }

        // 获取所有被 @ARouter 注解的 元素集合
        Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(ARouter.class);
        // 遍历所有的类节点
        for (Element element : elements) {
     
            // 获取类节点,获取包节点 (com.xiangxue.xxxxxx)
            String packageName = elementTool.getPackageOf(element).getQualifiedName().toString();

            // 获取简单类名,例如:MainActivity
            String className = element.getSimpleName().toString();
            messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>> 被@ARetuer注解的类有:" + className); // 打印出 就证明APT没有问题

            // 下面是练习 JavaPoet

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

            // 下毒,现在是 无法生成 【作业】

            // 1.方法
            /*MethodSpec mainMethod = 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();

            // 2.类
            TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .addMethod(mainMethod)
                    .build();

            // 3.包
            JavaFile packagef = JavaFile.builder("com.derry.study", helloWorld).build();

            // 去生成
            try {
                packagef.writeTo(filer);
            } catch (IOException e) {
                e.printStackTrace();
                messager.printMessage(Diagnostic.Kind.NOTE, "生成失败,请检查代码...");
            }*/

            // 先JavaPoet 写一个简单示例,方法--->类--> 包,是倒序写的思路哦
            /*
             package com.example.helloworld;

             public final class HelloWorld {

                 public static void main(String[] args) {
                    System.out.println("Hello, JavaPoet!");
                 }

             }

             */
            // 方法
            MethodSpec mainMethod = MethodSpec.methodBuilder("main")
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .returns(void.class)
                    .addParameter(System[].class, "args")
                    // 增加main方法里面的内容
                    .addStatement("$T.out.println($S)", System.class, "AAAAAAAAAAA!")
                    .build();
            // 类
            TypeSpec testClass = TypeSpec.classBuilder("Test")
                    .addMethod(mainMethod)
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .build();

            // 包
            // Program type already present: com.xiangxue.test22.Test
            JavaFile packagef = JavaFile.builder("com.xiangxue.test22", testClass).build();

            try {
     
                packagef.writeTo(filer);
            } catch (IOException e) {
     
                e.printStackTrace();
                messager.printMessage(Diagnostic.Kind.NOTE, "生成Test文件时失败,异常:" + e.getMessage());
            }
        }
        return true; // 坑:必须写返回值,表示处理@ARouter注解完成
    }
}

路由的参数传递功能

@paramter
String name; //在字段添加注解

public class Personal_MainActivity$$Parameter implements ParameterGet {
      
@Override
public void getParameter(Object targetParameter) {
      
    Personal_MainActivity t = (Personal_MainActivity) targetParameter; 
    t.name = t.getIntent().getStringExtra("name"); 
    t.sex = t.getIntent().getStringExtra("sex"); 
 } 
}

路由 组件本地图片、数据、其他方法通信 实现

  1. common 层继承标准规则,定义具体业务标准规则
  2. 具体实现交给具体组件
  3. 其他任意模块或组件都可以访问

Alibaba.Arouter分析

  1. 从外部URL映射到内部页面,以及参数传递与解析
  2. 跨模块页面跳转,模块间解耦
  3. 拦截跳转过程,处理登陆、埋点等逻辑
  4. 跨模块API调用,通过控制反转来做组件解耦

Arouter 的优化:ASM字节码插桩:设计就是遍历所有classes.dex,所有的源码 ,双重遍历加到缓存里面,非常耗时;

Native与H5的问题:因为在H5中是无法使用StartActivity()跳转到Native页面的,而从Native跳转到H5页面也只能通过配置浏览器的方式实现。

1.通俗易懂又全面

2.开源最佳实践

3.中文ARouter使用API​​

4.最详细的ARouter源码分析

5.Gradle自定义插件,热修复asm字节码插桩

你可能感兴趣的:(开源框架,android)