ARouter初始化及跳转原理

Posted ImportSUC

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ARouter初始化及跳转原理相关的知识,希望对你有一定的参考价值。

ARouter初始化及跳转原理

编译后生成文件

仓库类

``

class Warehouse 
    // Cache route and metas
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    static Map<String, RouteMeta> routes = new HashMap<>();

    // Cache provider
    static Map<Class, IProvider> providers = new HashMap<>();
    static Map<String, RouteMeta> providersIndex = new HashMap<>();

    // Cache interceptor
    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
    static List<IInterceptor> interceptors = new ArrayList<>();
    //省略部分代码

1.初始化代码追踪

ARouter.init(this);

进入ARouter.java

进入__ARouter.java

进入LogisticsCenter.java

``

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException 
    mContext = context;
    executor = tpe;

  //省略部分代码
            Set<String> routerMap;

            // It will rebuild router map every times when debuggable.
            //如果是debug模式,或者是新版本,则更新,否则直接从sp中获取
            if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) 
             		//关键代码1:获取“com.alibaba.android.arouter.routes”包名下的所有的class类名
             		//“com.alibaba.android.arouter.routes”即编译时生成的代码
                routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
                if (!routerMap.isEmpty()) 
                    context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();
                
                PackageUtils.updateVersion(context);    // Save new version name when router map update finishes.
             else 
                routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
            

						//进行实例化,只针对Root,Interceptor,provider
            for (String className : routerMap) 
                //com.alibaba.android.arouter.routes$$.ARouter$$Root
                if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_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 + SUFFIX_INTERCEPTORS)) 
                    // Load interceptorMeta
                    ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
                 else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) 
                    // Load providerIndex
                    ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                
            
				

1.首先通过包名获取包名下的class类名

2.反射进行实例化后,跳用loadInto,进行数据加载,将数据保存到Warehouse.groupsIndex

``

/**
 * DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Root$$app implements IRouteRoot 
  @Override
  public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) 
    routes.put("demo", ARouter$$Group$$demo.class);
    routes.put("uri", ARouter$$Group$$uri.class);
  

END

跳转

ARouter.getInstance().build(RouteConstant.LOGIN)
        .withString(LoginActivity.KEY_PATH, postcard.getPath())
        .navigation();

1.build

``

/**
 * Build postcard by path and default group
 */
protected Postcard build(String path) 
    if (TextUtils.isEmpty(path)) 
        throw new HandlerException(Consts.TAG + "Parameter is invalid!");
     else 
        PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
        if (null != pService) 
            path = pService.forString(path);
        
        return build(path, extractGroup(path));
    

如果有PathReplaceService,则进行路径替换。所以我们可以在项目中继承PathReplaceService来实现路径替换

``

protected Postcard build(String path, String group) 
    if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) 
        throw new HandlerException(Consts.TAG + "Parameter is invalid!");
     else 
        PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
        if (null != pService) 
            path = pService.forString(path);
        
        //关键代码 :创建Postcard对象。Postcard对象中包含了跳转所需要的class对象,参数等必须元素,此处只是设置了Postcard的path和group,其他属性的设置在navigation中完成
        return new Postcard(path, group);
    

2.navigation

Postcard.java

``

public Object navigation() 
    return navigation(null);

public Object navigation(Context context) 
        return navigation(context, null);
    
 public Object navigation(Context context, NavigationCallback callback) 
        return ARouter.getInstance().navigation(context, this, -1, callback);
    

ARouter.java

``

public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) 
    return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);

_ARouter.java

``

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) 
		//预处理服务
    PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
    if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) 
        // Pretreatment failed, navigation canceled.
        return null;
    

    try 
      //关键代码,对postcard剩余字段进行赋值
        LogisticsCenter.completion(postcard);
     catch (NoRouteFoundException ex) 
				//省略部分代码
        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);
    
		//greenChannel = true 时拦截器不工作,eg: fragment 的greenChannel 为true
    if (!postcard.isGreenChannel())    // It must be run in async thread, maybe interceptor cost too mush time made ANR.
        interceptorService.doInterceptions(postcard, new InterceptorCallback() 
            @Override
            public void onContinue(Postcard postcard) 
                _navigation(context, postcard, requestCode, callback);
            

            @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;

LogisiticsCenter.java

``

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.拿到group的class对象
        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 
                 //省略代码
								/********************关键代码****************/
                //通过class对象进行初始化
                IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
              	//将要跳转的activity roteMeta数据加载到Warehouse.routes
                iGroupInstance.loadInto(Warehouse.routes);
                Warehouse.groupsIndex.remove(postcard.getGroup());
  							//省略代码
             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;
        
    

``

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() 
          

以上是关于ARouter初始化及跳转原理的主要内容,如果未能解决你的问题,请参考以下文章

ARouter源码分析—— 路由跳转分析

ARouter的原理

Arouter之API原理解析

ARouter 在多 module 项目中实战

ARouter 在多 module 项目中实战

ARouter 在多 module 项目中实战