美文网首页
Aroute源码分析

Aroute源码分析

作者: freelifes | 来源:发表于2021-12-14 14:08 被阅读0次

Aroute优点:

1 :支持解析标准得URl进行跳转,并且自动注入参数到目标页面。
2 : 支持多模块工程使用。
3 :支持依赖注入,传递数据。
4 :支持多个拦截器,自定义拦截顺序。
5 : 支持MultiDex
6 : 支持获取service和fragment等。

Aroute原理

1 : 路由跳转,隐式Intent,维护action在多个模块繁琐。显示Intent,需要目标Class。各个模块需要引用Arouter.把所有的符合要求class获取和存储。通过路由找到目标class。
2 : 获取Service ,把所有service存到Arouter中,通过路由找到目标Service(provider)
3 : 依赖注入, 编译时期解析注解,创建需要赋值的class类 . 运行时期 通过类名反射创建对象,直接调用赋值。

Aroute模块

分为annotation api compiler app 和 moudle


arouter.png

路由跳转

1 : ArouterProcessor : 负责生成路由得root和group和provider的class
2 : AutowiredProcessor : 负责解析生成传输数据得解析。
3 : 如果使用插件,自动注册。 使用插件防止路由信息太多,加载较慢,内存占用较大,anr等问题。
4 :初始化。 遍历本地符合得class文件。

   final CountDownLatch countDownLatch = new CountDownLatch(paths.size());
        for (String path : paths) {
            DefaultPoolExecutor.getInstance().execute(new Runnable() {
                @Override
                public void run() {
                    DexFile dexFile = null;
                    try {
                        if (path.endsWith(EXTRACTIED_SUFFIX)) {
                            dexFile = DexFile.loadDex(path, path + ".tmp", 0);
                        } else {
                            dexFile = new DexFile(path);
                        }
                        Enumeration<String> dexEntries = dexFile.entries();
                        while (dexEntries.hasMoreElements()) {
                            String className = dexEntries.nextElement();
                            if (className.startsWith(packageName)) {
                                classNames.add(className);
                            }
                        }

5,6 :传入一个map去生成得class中加载所有得group。

static Map<String,Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
 Set<String> routerMap = ClassUtils.getFileNameByPackageName(context, Consts.ROUTE_ROOT_PACKAGE);
                for (String className : routerMap) {
                    if (className.startsWith(Consts.ROUTE_ROOT_PACKAGE + ".ARouter_Root")) {
                        ((IRouteRoot) Class.forName(className).getConstructor().newInstance()).loadInto(WareHouse.groupsIndex);
                    } else if (className.startsWith(Consts.ROUTE_ROOT_PACKAGE + ".ARouter_Provider")) {
                        ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(WareHouse.providerIndex);
                    }
                }

7 :路由跳转,通过传入得group,从刚才得map中得到组得class,反射创建该对象。
8,9 : 该对象再通过map把数据加载存储到wareHouse

  static Map<String, RouteMeta> routeMetaMap = new HashMap<>();

10 :warehouse 通过path得到RouteMeta,RouteMeta中包含了跳转所需要得class,类型,和参数,优先级等。如果是provider,则有provider等信息。

 public synchronized static void completion(PostCard postCard){
        if(null == postCard){
            throw  new RuntimeException("no postCard");
        }
        RouteMeta routeMeta = WareHouse.routeMetaMap.get(postCard.getPath());
        if(null == routeMeta){
            if(!WareHouse.groupsIndex.containsKey(postCard.getGroup())){
                throw new RuntimeException("no postcard");
            }else {
                addRouteGroupDynamic(postCard.getGroup(),null);
            }
           completion(postCard);
        }else {
            postCard.setDestination(routeMeta.getDestination());
            postCard.setType(routeMeta.getType());
            postCard.setPriority(routeMeta.getPriority());
            switch (routeMeta.getType()){
                case PROVIDER:
                    Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                    IProvider instance = WareHouse.providerMap.get(providerMeta);
                    if(instance == null){
                        IProvider provider;
                        try {
                            provider = providerMeta.getConstructor().newInstance();
                            provider.init(context);
                            WareHouse.providerMap.put(providerMeta,provider);
                            instance = provider;
                        }catch (Exception e){
                            e.printStackTrace();

11 :比如是activity类型,直接跳转。 如果是provider,拿到注解得那个provider对象,就可以使用provider中得方法。

  protected Object navigation(final Context context, final PostCard postCard, final NavigationCallback navigationCallback) {
        postCard.setContext(context == null ? mContext : context);
        LogisticsCenter.completion(postCard);
        switch (postCard.getType()) {
            case ACTIVITY:
                final Intent intent = new Intent(postCard.getContext(), postCard.getDestination());
                intent.putExtras(postCard.getBundle());
                if (!(postCard.getContext() instanceof Activity)) {
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                }
                runInMainThread(new Runnable() {
                    @Override
                    public void run() {
                        postCard.getContext().startActivity(intent);
                    }
                });
                break;
            case PROVIDER:
                return postCard.getProvider();
        }
        return null;
    }

依赖注入Autowired

autowired.png

1 .2 :都是第一幅图的逻辑。
3 :传递数据,通过bundle写入数据,intent传递。
4 : Arouter.getInstance().inject(this) 通过this类名得到生成的类的class。创建对象,把数据绑定到this上。

private void  doinject(Object object,Class parent){
        Class clazz = parent == null ? object.getClass() : parent;
        try {
            ISyringe iSyringe = (ISyringe) Class.forName(clazz.getName()+ Consts.SUFFIX_AUTOWIRED).getConstructor().newInstance();
            if(iSyringe != null){
                iSyringe.inject(object);
            }
            Class superclass = clazz.getSuperclass();
            if(null != superclass && !superclass.getName().startsWith("android")) {
                doinject(object, superclass);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

ArouterProcessor 路由跳转/获取服务

收集注解存到groupMap<group,routeMeta>():
for (Element element : routeElements) {
                TypeMirror tm = element.asType();
                Route route = element.getAnnotation(Route.class);
                RouteMeta routeMeta = null;
                if (types.isSubtype(tm, typeActivity)) {
                    routeMeta = new RouteMeta(route, element, RouteType.ACTIVITY);
                } else if (types.isSubtype(tm, typeProvider)) {
                    routeMeta = new RouteMeta(route, element, RouteType.PROVIDER);
                } else if (types.isSubtype(tm, typeService)) {
                    routeMeta = new RouteMeta(route, element, RouteType.SERVICE);
                }
                categories(routeMeta);
            }
生成class
 switch (routeMeta.getType()) {
                        case PROVIDER:
                            TypeElement rawType = (TypeElement) routeMeta.getRawType();
                            List<? extends TypeMirror> interfaces = rawType.getInterfaces();
                            for (TypeMirror tm : interfaces) {
                                if (types.isSameType(tm, typeProvider)) {
                                    loadIntoMethodofProviderBuilder.addStatement("providers.put($S,$T.build($T." + routeMeta.getType() + ",$T.class,$S,$S," + routeMeta.getPriority() + "))",
                                            routeMeta.getRawType().toString(),
                                            routeMetaCn,
                                            routeMetaCn,
                                            className,
                                            routeMeta.getPath(),
                                            routeMeta.getGroup());
                                } else if (types.isSubtype(tm, typeProvider)) {
                                    loadIntoMethodofProviderBuilder.addStatement("providers.put($S,$T.build($T." + routeMeta.getType() + ",$T.class,$S,$S," + routeMeta.getPriority() + "))",
                                            tm.toString(),
                                            routeMetaCn,
                                            routeTypeCn,
                                            className,
                                            routeMeta.getPath(),
                                            routeMeta.getGroup());
                                }
                            }
                            break;
                        default:
                            break;

生成provider,为什么要区分types.isSameType和types.isSubType? -- 接口隔离
例1 : B moudle 定义一个带路由的SerVice, A moudle 没有依赖B , 现在A想通过路由拿到这个SerVice。 路由拿到了,但是没办法使用这个对象。
解决: 定义一个公共的BaseService,定义公共方法,A,B都依赖这个Service,当A拿到B这个SerVice对象的时候,使用BaseService去接收和使用。
例2 : AppMoudle 依赖Amoudle 现在Amoudle想拿到AppMoudle中的数据, 平时我们写个方法跳转转递,现在只需要在Amoudle中定义一个Service。AppMoudle实现它,在AMoudle中,主动获取就可以了。

生成group
                            routeMeta.getPath(),
                            routeMetaCn,
                            routeTypeCn,
                            className,
                            routeMeta.getPath().toLowerCase(),
                            routeMeta.getGroup().toLowerCase());
                }
                //生成groups
                String groupFileName = Consts.NAME_OF_GROUP + groupName;
                JavaFile.builder(Consts.PACKAGE_OF_GENERATE_FILE, TypeSpec.classBuilder(groupFileName)
                        .addSuperinterface(ClassName.get(typeGroup))
                        .addModifiers(Modifier.PUBLIC)
                        .addMethod(loadInfoMethodOfGroupBuilder.build())
                        .build()).build().writeTo(filer);
                rootMap.put(groupName, groupFileName);
            }
            if (MapUtils.isNotEmpty(rootMap)) {
                for (Map.Entry<String, String> entry : rootMap.entrySet()) {
                    loadIntoMethodRootBuilder.addStatement("routers.put($S,$T.class)", entry.getKey(), ClassName.get(Consts.PACKAGE_OF_GENERATE_FILE, entry.getValue()));
                }
            }

AutoWiredProcessor 参数依赖注入

收集Map
Map<TypeElement, List<Element>> parentAndChild = new HashMap<>();
生成class

1 支持provider的成员变量。
2 支持bundle基本类型,序列化对象传递。
3 支持object对象传递和解析。解析object对象使用serializationService
解析如下:

    substitute.dou = substitute.getArguments().getDouble("dou", substitute.dou);
    substitute.ser = (com.alibaba.android.arouter.demo.service.model.TestSerializable) substitute.getArguments().getSerializable("ser");
    substitute.pac = substitute.getArguments().getParcelable("pac");
    if (null != serializationService) {
      substitute.objList = serializationService.parseObject(substitute.getArguments().getString("objList"),
              new com.alibaba.android.arouter.facade.model.TypeWrapper<List<TestObj>>(){}.getType());
    } else {
      Log.e("ARouter::", "You want automatic inject the field 'objList' in class 'BlankFragment' , then you should implement 'SerializationService' to support object auto inject!");
    }

对象传递如下:

 public Postcard withObject(@Nullable String key, @Nullable Object value) {
        serializationService = ARouter.getInstance().navigation(SerializationService.class);
        mBundle.putString(key, serializationService.object2Json(value));
        return this;
    }

5 获取service的两种方式:

  public void inject(Object object) {
        //  AutoWiredServiceImpl navigation1 = (AutoWiredServiceImpl) Arouter.getInstance().navigation(AutoWireService.class);
        AutoWireService navigation = (AutoWireService) Arouter.getInstance().build("/lisi/service/autowired").navigation();
        navigation.autoWire(object);
    }

注入- 绑定数据给当前对象

   Arouter.getInstance().inject(this);

总结

Arouter 收集数据,收集class,都存储在对象中,再依据路由调用,获取数据,class,分发给各个moudle。类似于加工平台和中转站。
Arouter 几个优点,互不依赖的moudle相互跳转,传递数据,支持Uri,支持优先级,这几个优点利于组件开发,高内聚,低耦合。

相关文章

网友评论

      本文标题:Aroute源码分析

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