ARouter源码分析初始化以及跳转

来源:互联网 发布:nba球员体测数据 编辑:程序博客网 时间:2024/06/06 06:30

这里只分析最简单的操作 , 初始化和跳转
先看一下要跳转的Activity需要添加@Route注解

@Route(path = "/simple/simpleActivity")public class SimpleActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_simple);    }}

之后再build一下 , 会看到以下目录中出现注解处理后的三个类

这里写图片描述

那么从初始化开始

    /**     * Init, it must be call before used router.     */    public static void init(Application application) {        if (!hasInit) {            logger = _ARouter.logger;            _ARouter.logger.info(Consts.TAG, "ARouter init start.");            hasInit = _ARouter.init(application);            if (hasInit) {                _ARouter.afterInit();            }            _ARouter.logger.info(Consts.TAG, "ARouter init over.");        }    }

调用了_ARouter的init()方法

    private volatile static ThreadPoolExecutor executor = DefaultPoolExecutor.getInstance();    protected static synchronized boolean init(Application application) {        mContext = application;        LogisticsCenter.init(mContext, executor);        logger.info(Consts.TAG, "ARouter init success!");        hasInit = true;        // It's not a good idea.        // if (Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {        //     application.registerActivityLifecycleCallbacks(new AutowiredLifecycleCallback());        // }        return true;    }

在_ARouter类里的 mContext保存了初始化时的传过来的application , 接着调用了LogisticsCenter的init()方法传入mContext , 和线程池(核心线程数 : CPU + 1 , 最大线程数 : 20)

    public static final String SEPARATOR = "$$";    public static final String DOT = ".";    public static final String SDK_NAME = "ARouter";    /**     * LogisticsCenter init, load all metas in memory. Demand initialization     */    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {        mContext = context;        executor = tpe;        try {            // These class was generate by arouter-compiler.            List<String> classFileNames = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);            for (String className : classFileNames) {                if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + "Root")) {                    // This one of root elements, load root.                    ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + "Interceptors")) {                    // Load interceptorMeta                    ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);                } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + "Providers")) {                    // Load providerIndex                    ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);                }            }            if (Warehouse.groupsIndex.size() == 0) {                logger.error(TAG, "No mapping files were found, check your configuration please!");            }            if (ARouter.debuggable()) {                logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));            }        } catch (Exception e) {            throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");        }    }

//LogisticsCenter 当做物流中心 , 将在编译期利用注解器产生的文件存到Warehouse(仓库)里面 ,

public static final String ROUTE_ROOT_PAKCAGE = “com.alibaba.android.arouter.routes”;

首先它会调用ClassUtils.getFileNameByPackageName()获取所有上面这个包名的类 , 除了上面app中编译器产生的类之外 , arouter-api也会创建三个类

ARouter$$Group$$arouterARouter$$Providers$$arouterapiARouter$$Root$$arouterapi

找到所有类型之后 , 有三个分支判断类名的开头

com.alibaba.android.arouter.routes.ARouter$$Rootcom.alibaba.android.arouter.routes.ARouter$$Interceptorscom.alibaba.android.arouter.routes.ARouter$$Providers

首先看看Root开头的类

public class ARouter$$Root$$app implements IRouteRoot {  @Override  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {    routes.put("simple", ARouter$$Group$$simple.class);  }}
public class ARouter$$Root$$arouterapi implements IRouteRoot {  @Override  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {    routes.put("arouter", ARouter$$Group$$arouter.class);  }}

第一个在自己的模块当中产生得类 , 后缀为app
第二个是在arouter-api中产生的类 , 后缀为arouterapi

(Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);

利用反射获取实例 , 并且调用了loadInto()方法 , 传过去的参数是Warehouse.groupsIndex

class Warehouse {    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();}

传过去的是一个静态的HashMap , 也就是说将“组”的信息 , 以“组名” , “组类”以键值对的方式存入了 , Warehouse 的 groupsIndex 里面 , 从名字上看就是存储“组”的 .

看过ARouter的github上的介绍可以知道 , 他是以懒加载的方式执行的 , 也就是说你当前没有用到该类的跳转 , 那么他不会把映射关系存到内存当中也就是groupIndex当中去 , 这里也体现了这一点 , 只是将“组的信息”存到内存 , 具体的类并没有映射关系 .

接下来的分支是Interceptors , 这里咱们没有自定义拦截器 , 并且arouter-api当中也没有 , 所以就跳过 .

第三个分支是Provider

public class ARouter$$Providers$$app implements IProviderGroup {  @Override  public void loadInto(Map<String, RouteMeta> providers) {  }}
public class ARouter$$Providers$$arouterapi implements IProviderGroup {  @Override  public void loadInto(Map<String, RouteMeta> providers) {    providers.put("AutowiredService", RouteMeta.build(RouteType.PROVIDER, AutowiredServiceImpl.class, "/arouter/service/autowired", "arouter", null, -1, -2147483648));    providers.put("InterceptorService", RouteMeta.build(RouteType.PROVIDER, InterceptorServiceImpl.class, "/arouter/service/interceptor", "arouter", null, -1, -2147483648));  }}

同样第一个是app的 , 第二个是arouter-api的 .
作用也是和上面一样 , 传入Warehouse.providersIndex参数 , 用HashMap来存储.
这里是以 名称RouteMeta为键值对存储 , RouteMeta保存着一些路由所需要的一些基本信息 , 例如路径 , 组名 , 类名等等 .
AutowiredService : 用来自动注入传递的参数的
InterceptorService : 用来拦截 , 所有的拦截都在这个类的实现类InterceptorServiceImpl中进行

存储所有映射关系后 , 下面就是一些log信息了 , 这样LogisticsCenter的初始化就结束了 , 之后会调用_ARouter的afterInit()方法

    static void afterInit() {        // Trigger interceptor init, use byName.        interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();    }

这里是给全局拦截器 InterceptorServiceImpl 赋值 , 这个是arouter-api中的类 , 这里调用了 init()方法 , 将自己实现的拦截器存入仓库中 , 并且都调用了init()方法 .

至此 , 初始化就完成了 , 那么接下来就是跳转了

ARouter.getInstance().build("/simple/simpleActivity")                        .navigation(this);

接着看一下是如何根据路径去寻找相应信息并且实现跳转以及其他的实现的 .

    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 autoinject.                    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 be implememt 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. build()返回一个PostCard对象 , 包含路径 , 组名
2. 调用PostCard的navigation()方法 , navigation()方法中调用LogisticsCenter.completion()方法并把包含路径 , 组名的postCard传过去 .
3. 重点!!! 接下来回去Warehouse(仓库)中搜索 , 详细仓库存什么看下面 , 首先会去从 routes 去寻找具体的信息 , 如果没有 , 去groupsIndex 从组中去寻找 , 找到了相应的信息 , 通过反射获取实例 , 添加到routes 缓存中 , 并且从groupsIndex 中去掉 .
4. 找到相应的信息之后 , 给postCard , 再去设置 类 , 类型(这里指Activity或者Fragment等等) , 优先级 , 传递过去的额外数据 .
5. 在接着根据postcard的类型判断 , 如果是Fragment或者PROVIDER类型 , 会开启绿色通道(不会被拦截) , 除了上述两个类 , 如果你没有手动设置绿色通道 , 他都会被arouter-api中的全局拦截器被拦截掉(但不会被消耗) , 注意:如果在上述环节中出现异常 , 那么他会根据你是否在 navigation()方法返回了callback判断 , 如果传了callback , 那么会调用callback的onLost()方法 , 要是没有传 , 会调用 DegradeService 的 onLost()方法 , DegradeService 是个接口 , 如果你需要回调 , 继承这个类就可以 , demo中显示为全局降级 .

class Warehouse {    //存储 需要路由跳转的"组"信息    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();    //存储 需要跳转的具体对象的信息    static Map<String, RouteMeta> routes = new HashMap<>();    //存储具体provider的信息    static Map<Class, IProvider> providers = new HashMap<>();    //存储 provider"组"信息 , 和上面是一个意思    static Map<String, RouteMeta> providersIndex = new HashMap<>();    //存储 拦截器"组"信息    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");    //存储 具体拦截器    static List<IInterceptor> interceptors = new ArrayList<>(); }
    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {        try {            LogisticsCenter.completion(postcard);        } catch (NoRouteFoundException ex) {            logger.warning(Consts.TAG, ex.getMessage());            if (debuggable()) { // Show friendly tips for user.                Toast.makeText(mContext, "There's no route matched!\n" +                        " Path = [" + postcard.getPath() + "]\n" +                        " Group = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();            }            if (null != callback) {                callback.onLost(postcard);            } else {    // No callback for this invoke, then we use the global degrade service.                DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);                if (null != degradeService) {                    degradeService.onLost(context, postcard);                }            }            return null;        }        if (null != callback) {            callback.onFound(postcard);        }        //上面分析到了这里        if (!postcard.isGreenChannel()) {   // It must be run in async thread, maybe interceptor cost too mush time made ANR.            interceptorService.doInterceptions(postcard, new InterceptorCallback() {                /**                 * Continue process                 *                 * @param postcard route meta                 */                @Override                public void onContinue(Postcard postcard) {                    _navigation(context, postcard, requestCode, callback);                }                /**                 * Interrupt process, pipeline will be destory when this method called.                 *                 * @param exception Reson of interrupt.                 */                @Override                public void onInterrupt(Throwable exception) {                    if (null != callback) {                        callback.onInterrupt(postcard);                    }                    logger.info(Consts.TAG, "Navigation failed, termination by interceptor : " + exception.getMessage());                }            });        } else {            return _navigation(context, postcard, requestCode, callback);        }        return null;    }

根据postCard是否为绿色通道判断 , 如果不是会被全局拦截器 InterceptorServiceImpl 拦截 , 调用doInterceptions()方法 , 这里会按顺序挨个调用所有自定义的拦截器的process()方法 , process()方法是执行在子线程当中 . 在执行完所有拦截器之后 , 会调用_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);                }                // Navigation in main looper.                new Handler(Looper.getMainLooper()).post(new Runnable() {                    @Override                    public void run() {                        if (requestCode > 0) {  // Need start for result                            ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());                        } else {                            ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());                        }                        if ((0 != postcard.getEnterAnim() || 0 != postcard.getExitAnim()) && currentContext instanceof Activity) {    // Old version.                            ((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());                        }                        if (null != callback) { // Navigation over.                            callback.onArrival(postcard);                        }                    }                });                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;    }

这里就是最终的方法了 , 根据 type 来执行最终操作 , 现在这个版本目前实现了Activity跳转 , 获取Fragment实例和获取Provider的实例 .

总结

  1. ARouter在利用在编译器产生若干个类 , 并在初始化中把这些类的信息存到Warehouse当中 .
  2. 跳转时会根据Warehouse的内存中寻找 , 实现懒加载 .
  3. 现阶段的版本提供了Activity , Fragment , Provider类型的实现 , 其中Provider和Fragment , 为绿色通道 , 拦截器无法拦截 .
  4. 自定义的拦截器是在全局拦截器中执行 , 并且会根据优先级遍历所有自定义拦截器 . 拦截器的process()方法执行在子线程当中 .
1 0
原创粉丝点击