ARouter-几种APT生成的类

1,218 阅读5分钟

模块名是配置在build.gradle中的参数,一般情况下是module名称,如app或其他自定义的module名称:

android {
    defaultConfig {
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: "enable"]
            }
        }
    }
}

ARouter?Root?模块名.class

​ 这个类实现了IRouteRoot接口,记录了所有的分组信息,通过group名称,可以找到对应group下 所有的路由信息。如demo中的例子:

public class ARouter?Root?app implements IRouteRoot {
    public ARouter?Root?app() {
    }

    public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
        routes.put("test", test.class);
        routes.put("yourservicegroupname", yourservicegroupname.class);
    }
}

​ 通过区分group可以实现路由表的懒加载,只有用到某个group时才将它下面的所有路由信息加载到内存中,减少初始化的时间和内存占用。具体实现过程在LogisticsCenter.completion()中:

    public synchronized static void completion(Postcard postcard) {
        if (null == postcard) {
            throw new NoRouteFoundException(TAG + "No postcard!");
        }

        RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
        if (null == routeMeta) {    // Maybe its does't exist, or didn't load.
            Class<? extends IRouteGroup> groupMeta = Warehouse.groupsIndex.get(postcard.getGroup());  // Load route meta.
            if (null == groupMeta) {
                throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
            } else {
                // Load route and cache it into memory, then delete from metas.
                try {
                    if (ARouter.debuggable()) {
                        logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                    }

                    IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                    iGroupInstance.loadInto(Warehouse.routes);
                    Warehouse.groupsIndex.remove(postcard.getGroup());

                    if (ARouter.debuggable()) {
                        logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] has already been loaded, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
                    }
                } catch (Exception e) {
                    throw new HandlerException(TAG + "Fatal exception when loading group meta. [" + e.getMessage() + "]");
                }

                completion(postcard);   // Reload
            }
        } else {
            postcard.setDestination(routeMeta.getDestination());
            postcard.setType(routeMeta.getType());
            postcard.setPriority(routeMeta.getPriority());
            postcard.setExtra(routeMeta.getExtra());

            Uri rawUri = postcard.getUri();
            if (null != rawUri) {   // Try to set params into bundle.
                Map<String, String> resultMap = TextUtils.splitQueryParameters(rawUri);
                Map<String, Integer> paramsType = routeMeta.getParamsType();

                if (MapUtils.isNotEmpty(paramsType)) {
                    // Set value by its type, just for params which annotation by @Param
                    for (Map.Entry<String, Integer> params : paramsType.entrySet()) {
                        setValue(postcard,
                                params.getValue(),
                                params.getKey(),
                                resultMap.get(params.getKey()));
                    }

                    // Save params name which need auto inject.
                    postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
                }

                // Save raw uri
                postcard.withString(ARouter.RAW_URI, rawUri.toString());
            }

            switch (routeMeta.getType()) {
                case PROVIDER:  // if the route is provider, should find its instance
                    // Its provider, so it must implement IProvider
                    Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
                    IProvider instance = Warehouse.providers.get(providerMeta);
                    if (null == instance) { // There's no instance of this provider
                        IProvider provider;
                        try {
                            provider = providerMeta.getConstructor().newInstance();
                            provider.init(mContext);
                            Warehouse.providers.put(providerMeta, provider);
                            instance = provider;
                        } catch (Exception e) {
                            throw new HandlerException("Init provider failed! " + e.getMessage());
                        }
                    }
                    postcard.setProvider(instance);
                    postcard.greenChannel();    // Provider should skip all of interceptors
                    break;
                case FRAGMENT:
                    postcard.greenChannel();    // Fragment needn't interceptors
                default:
                    break;
            }
        }
    }

流程如下:

  1. 查询某个path的路由信息是否存在
  2. 查询该group的组信息
  3. 将该group下的所有路由信息全部加载到内存中
  4. 重新加载该path,根据类型和路由存储的类信息,加载对应的对象实例(对PROVIDER和FRAGMENT做特殊处理,标记不需要调用拦截器,以及调用IProvider的init(context)方法)

ARouter?Providers?模块名.class

​ 这个类实现了IProviderGroup接口,主要记录了服务提供者的接口的全限定类名和具体的类信息,服务提供者都是实现了IProvider的类。

​ 作用是能根据具体的服务接口来实例化服务,只对接口只有一个实现类时有效,如果有两个类实现了某个服务接口,不能保证通过类型获得的服务的具体类型:

有两个类HelloServiceImpl和HelloService2实现HelloService接口,APT生成的注册类如下:
public class ARouter?Providers?app implements IProviderGroup {
    public ARouter?Providers?app() {
    }

    public void loadInto(Map<String, RouteMeta> providers) {
        providers.put("com.alibaba.android.arouter.demo.testservice.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloServiceImpl.class, "/yourservicegroupname/hello", "yourservicegroupname", (Map)null, -1, -2147483648));
        providers.put("com.alibaba.android.arouter.demo.testservice.HelloService", RouteMeta.build(RouteType.PROVIDER, HelloService2.class, "/yourservicegroupname/hello2", "yourservicegroupname", (Map)null, -1, -2147483648));
        providers.put("com.alibaba.android.arouter.facade.service.SerializationService", RouteMeta.build(RouteType.PROVIDER, JsonServiceImpl.class, "/yourservicegroupname/json", "yourservicegroupname", (Map)null, -1, -2147483648));
        providers.put("com.alibaba.android.arouter.demo.testservice.SingleService", RouteMeta.build(RouteType.PROVIDER, SingleService.class, "/yourservicegroupname/single", "yourservicegroupname", (Map)null, -1, -2147483648));
    }
}

​ 可以看到调用了两次map的put方法,key是接口的全限定名,value是两个具体的实现类,运行时只有后面的put有效,所以实际的效果跟APT处理时的顺序有关。所以在这种情况下应该根据路由的名称来获取具体的服务类。

ARouter?Interceptors?模块名.class

​ 这个类实现了IInterceptorGroup接口,保存了拦截器和优先级。

public class ARouter?Interceptors?app implements IInterceptorGroup {
    public ARouter?Interceptors?app() {
    }

    public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
        interceptors.put(7, Test1Interceptor.class);
    }
}

​ 拦截器的使用在InterceptorServiceImpl._execute()中,调用在 _ARouter.navigation()中。考虑到拦截可能是异步的,所以InterceptorServiceImpl.doInterceptions()执行拦截时使用了CancelableCountDownLatch确保所有的拦截器都被处理之后,再进行后续操作。

public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
    if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
		checkInterceptorsInitStatus();
		if (!interceptorHasInit) {
            callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
            return;
        }
        LogisticsCenter.executor.execute(new Runnable() {
            @Override
            public void run() {
                CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
                try {
                    _execute(0, interceptorCounter, postcard);
                    interceptorCounter.await(postcard.getTimeout(), TimeUnit.SECONDS);
                    if (interceptorCounter.getCount() > 0) {    // Cancel the navigation this time, if it hasn't return anythings.
                        callback.onInterrupt(new HandlerException("The interceptor processing timed out."));
                    } else if (null != postcard.getTag()) {    // Maybe some exception in the tag.
                        callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
                    } else {
                        callback.onContinue(postcard);
                    }
                } catch (Exception e) {
                    callback.onInterrupt(e);
                }
            }
        });
    } else {
        callback.onContinue(postcard);
    }
}

ARouter?Group?Group名称.class

​ 这个类实现了IRouteGroup接口,记录了同一个group下所有的路由信息,包括activity,fragment,IProvider。支持的类型定义在RouteType的枚举中:

public enum RouteType {
    ACTIVITY(0, "android.app.Activity"),
    SERVICE(1, "android.app.Service"),
    PROVIDER(2, "com.alibaba.android.arouter.facade.template.IProvider"),
    CONTENT_PROVIDER(-1, "android.app.ContentProvider"),
    BOARDCAST(-1, ""),
    METHOD(-1, ""),
    FRAGMENT(-1, "android.app.Fragment"),
    UNKNOWN(-1, "Unknown route type");
}

​ 路由信息实现了通过一个字符串找到对应的类,做到了代码层面的解耦。

​ 路由信息的使用在_ARouter.__navigation()方法中,针对不同的类型有不同的处理方式:跳转或者获取具体的实例。

private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
    final Context currentContext = null == context ? mContext : context;
    switch (postcard.getType()) {
        case ACTIVITY:
            // Build intent
            final Intent intent = new Intent(currentContext, postcard.getDestination());
            intent.putExtras(postcard.getExtras());
			// Set flags.
            int flags = postcard.getFlags();
            if (-1 != flags) {
                intent.setFlags(flags);
            } else if (!(currentContext instanceof Activity)) {    // Non activity, need less one flag.
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            // Set Actions
            String action = postcard.getAction();
            if (!TextUtils.isEmpty(action)) {
                intent.setAction(action);
            }
			// Navigation in main looper.
            runInMainThread(new Runnable() {
                @Override
                public void run() {
                    startActivity(requestCode, currentContext, intent, postcard, callback);
                }
            });
            break;
        case PROVIDER:
            return postcard.getProvider();
        case BOARDCAST:
        case CONTENT_PROVIDER:
        case FRAGMENT:
            Class fragmentMeta = postcard.getDestination();
            try {
                Object instance = fragmentMeta.getConstructor().newInstance();
                if (instance instanceof Fragment) {
                    ((Fragment) instance).setArguments(postcard.getExtras());
                } else if (instance instanceof android.support.v4.app.Fragment) {
                    ((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());
                }
                return instance;
           } catch (Exception ex) {
                logger.error(Consts.TAG, "Fetch fragment instance error, " + TextUtils.formatStackTrace(ex.getStackTrace()));
           }
        case METHOD:
        case SERVICE:
        default:
            return null;
    }

    return null;
}

自定义的Activity?ARouter?Autowired.class

​ 这个类实现了ISyringe接口,主要的作用是为使用了@Autowired注解的activity的属性进行注入。流程:

  1. APT搜集activity中的@Aurowired注解,生成一个activity?ARouter?Autowired.class的类
  2. activity在onCreate()方法中调用ARouter.getInstance().inject(this);
  3. ARouter通过路由("/arouter/service/autowired")实例化AutowiredServiceImpl.java
  4. AutowiredServiceImpl.autowire()根据传入的activity的名称找到对应的activity?ARouter?Autowired.class并实例化,强转成ISyringe接口,并调用inject()方法
  5. 在inject()中,调用activity.getIntent().getxxx,获取到各个属性

如TestAct中有两个属性加了注解(Autowired跟Route路由注解无关):

public class TestAct extends Activity {
    @Autowired
    int age;
    @Autowired
    String name;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ARouter.getInstance().inject(this);
    }
}

生成的类如下,从intent中获取参数:

public class TestAct?ARouter?Autowired implements ISyringe {
    private SerializationService serializationService;

    public TestAct?ARouter?Autowired() {
    }

    public void inject(Object target) {
        this.serializationService = (SerializationService)ARouter.getInstance().navigation(SerializationService.class);
        TestAct substitute = (TestAct)target;
        substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
        substitute.name = substitute.getIntent().getExtras() == null ? substitute.name : substitute.getIntent().getExtras().getString("name", substitute.name);
    }
}