美文网首页
组件化开发-手写路由

组件化开发-手写路由

作者: 有腹肌的豌豆Z | 来源:发表于2020-10-18 12:57 被阅读0次

该框架仿照Arouter实现的,目的是学习Arouter框架。

框架的实现主要包括router_core、router_annotation和router_compiler三个部分。

  • annotation-api:核心api,用来实现路由模块的跳转功能;
  • annotation:自定义注解,用来声明需要路由的页面;
  • annotation-compiler:处理注解,在编译时根据自定义注解生成注册路由表的Java类;

annotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface Route {
    String path();
}

annotation-compiler

@AutoService(Processor.class) // 注册注解处理器到虚拟机
public class Process extends AbstractProcessor {

    Filer filer; // 文件操作

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        filer = processingEnv.getFiler();
    }

    /**
     * 返回支持的Java版本
     *
     * @return
     */
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return processingEnv.getSourceVersion();
    }

    /**
     * 添加 目标注解
     *
     * @return
     */
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> types = new HashSet<>();
        types.add(Route.class.getCanonicalName());
        return types;
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        //生成文件代码
        Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(Route.class);
        Map<String, String> map = new HashMap<>();
        for (Element element : elementsAnnotatedWith) {
            // TypeElement
            // VariableElement
            TypeElement typeElement = (TypeElement) element;
            //com.ysten.fuxi01.MainActivity
            String className = typeElement.getQualifiedName().toString();
            String pathName = typeElement.getAnnotation(Route.class).path();
            map.put(pathName, className + ".class");
        }
        if (map.size() == 0) {
            return false;
        }

        //
        Writer writer = null;
        //
        String className = "ActivityUtils" + System.currentTimeMillis();
        try {
            JavaFileObject classFile = filer.createSourceFile("com.shark.router." + className);
            writer = classFile.openWriter();
            writer.write("package com.shark.router;\n" +
                    "\n" +
                    "import com.sharkz.annotation_api.Arouter;\n" +
                    "import com.sharkz.annotation_api.IRouter;\n" +
                    "\n" +
                    "public class " + className + " implements IRouter {\n" +
                    "    @Override\n" +
                    "    public void putActivity() {\n");

            Iterator<String> iterator = map.keySet().iterator();
            while (iterator.hasNext()) {
                String activityKey = iterator.next();
                String cls = map.get(activityKey);
                writer.write("        Arouter.getInstance().putActivity(");
                writer.write("\"" + activityKey + "\"," + cls + ");");
            }
            writer.write("\n}\n" +
                    "}");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return false;
    }
}


build.gradle

plugins {
    id 'java-library'
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // 系统的注解处理器
    implementation 'com.google.auto.service:auto-service:1.0-rc6'
    annotationProcessor 'com.google.auto.service:auto-service:1.0-rc6'

    // 目前没有用到 另外一种形式 生成代码的
    // implementation 'com.squareup:javapoet:1.12.1'

    // 定义注解的module
    implementation project(path: ':annotation')
}

java {
    sourceCompatibility = JavaVersion.VERSION_1_7
    targetCompatibility = JavaVersion.VERSION_1_7
}

annotation-api

public interface IRouter {
    void putActivity();
}
public class Arouter {

    private static Arouter instance;
    private Context mContext;
    private static Map<String, Class<? extends Activity>> activityMap;

    /**
     * 获取到单例
     *
     * @return
     */
    public static Arouter getInstance() {
        if (instance == null) {
            synchronized (Arouter.class) {
                instance = new Arouter();
                activityMap = new ArrayMap<>();
            }

        }
        return instance;
    }

    /**
     * 添加 Activity到 路由表
     *
     * @param activityName 路径名
     * @param cls          com.sharkz.login.LoginActivity.class 全路径class name
     */
    public void putActivity(String activityName, Class cls) {
        if (cls != null && !TextUtils.isEmpty(activityName)) {
            activityMap.put(activityName, cls);
        }
    }

    /**
     * 初始化 必须在Application 中初始化
     *
     * @param context app
     */
    public void init(Context context) {
        mContext = context;
        // 这里的 com.shark.router 就是注解处理器里面的 自动生成代码的包名 一定要一样 否则获取不到数据
        List<String> className = getAllActivityUtils("com.shark.router");
        for (String cls : className) {
            try {
                Class<?> aClass = Class.forName(cls);
                if (IRouter.class.isAssignableFrom(aClass)) {
                    IRouter iRouter = (IRouter) aClass.newInstance();
                    iRouter.putActivity();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 界面 跳转
     *
     * @param activityName 目标 Activity的路径
     */
    public void jumpActivity(String activityName) {
        jumpActivity(activityName, null);
    }

    /**
     * 界面跳转
     *
     * @param activityName 目标Activity的绝对路径
     * @param bundle       传递的参数
     */
    public void jumpActivity(String activityName, Bundle bundle) {
        Intent intent = new Intent();
        Class<? extends Activity> aCls = activityMap.get(activityName);
        if (aCls == null) {
            Log.e("wangjitao", " error -- > can not find activityName " + activityName);
            return;
        }
        if (bundle != null) {
            intent.putExtras(bundle);
        }
        intent.setClass(mContext, aCls);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        // TODO 是不是很熟悉了
        mContext.startActivity(intent);
    }

    /**
     * 从 DexFile 里面获取 添加到路由表的数据
     *
     * @param packageName
     * @return
     */
    public List<String> getAllActivityUtils(String packageName) {
        List<String> list = new ArrayList<>();
        String path;
        try {
            path = mContext.getPackageManager().getApplicationInfo(mContext.getPackageName(), 0).sourceDir;
            DexFile dexFile = null;
            dexFile = new DexFile(path);
            Enumeration enumeration = dexFile.entries();
            while (enumeration.hasMoreElements()) {
                String name = (String) enumeration.nextElement();
                if (name.contains(packageName)) {
                    list.add(name);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

}

Demo

相关文章

  • 组件化开发-手写路由

    该框架仿照Arouter实现的,目的是学习Arouter框架。 框架的实现主要包括router_core、rout...

  • 路由组件化

    撸一个简单路由RouteriOS 组件化与路由的本质App 的组件化之路

  • 插件化原理

    比较阿里开源组件化和插件化框架的区别 name模块化开发模块间路由动态加载热修复兼容性问题组件化ARouter支持...

  • kotlin完成的项目

    项目是基于kotlin写的: Android 端: 1.使用组件化模块开发基于阿里ARouter封装的组件路由调用...

  • iOS-组件化-(跳转+传参数)

    iOS开发中组件化之业务组件间通讯方式之路由[https://www.jianshu.com/p/862564d4...

  • react 路由传参 高阶组件

    路由 手写路由 控制地址栏 歌手 根据改变渲染不同的组件

  • SogouModuleBus

    目前,组件化开发基本已经成为每一个公司必选的开发方案。开源的组件化路由框架也有很多,例如ARouter,CC等,作...

  • 戏说移动江湖开发历程

    大主线 细说移动开发历程 大技术 组件化开发 组件路由 组件配置动态加载 组件骨架架构插件化开发...

  • vue项目基建

    路由模块化 , 高频全局组件模块化 权限

  • iOS 组件化2

    组件化2 本文主要讲组件化之间是如何通讯的 组件化通讯方案 1、URL路由 2、target-action 3、p...

网友评论

      本文标题:组件化开发-手写路由

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