ARouter 源码解析(1.5.2 版本)

1、简介
  • ARouter 是阿里巴巴开源的 Android 平台中对页面、服务提供路由功能的中间件,通俗来讲就是一个用于帮助 Android App 进行组件化改造的框架,并且支持模块间的路由、通信、解耦等等。
  • 官方网站
    ARouter 介绍
2、ARouter 配置与基本用法
2.1 依赖引入与配置
// 根目录的 build.gradle
buildscript {
    dependencies {
        classpath 
        // ARouter
        classpath "com.alibaba:arouter-register:1.0.2"
    }
}

// 模块的 build.gradle
plugins {
    id 'kotlin-kapt'
}
kapt {
    arguments {
        // 根据模块名来命名路由根节点
        arg("AROUTER_MODULE_NAME", project.getName())
        // 生成 Json 文件
        arg("AROUTER_GENERATE_DOC", "enable")
    }
}
dependencies {
    // ARouter
    implementation 'com.alibaba:arouter-api:1.5.2'
    // 注意这里的 arouter-compiler 不能使用 1.5.2 版本,不然会编译不过
    kapt 'com.alibaba:arouter-compiler:1.2.2'
}
2.2 基本用法
@Route(path = "/home/main", group = "home")
class HomeMainActivity : AppCompatActivity() {

    @Autowired
    @JvmField
    var name: String? = null

    @Autowired
    @JvmField
    var age: Int? = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_trade_detail)
        ARouter.getInstance().inject(this)
    }
}

// 注入参数和服务
ARouter.getInstance().inject(this)

// 构建标准的路由请求
ARouter.getInstance().build("/home/main").navigation();

// 构建标准的路由请求,并指定分组
ARouter.getInstance().build("/home/main", "ap").navigation();

// 构建标准的路由请求,通过 Uri 直接解析
Uri uri;
ARouter.getInstance().build(uri).navigation();

// 构建标准的路由请求,startActivityForResult
// navigation的 第一个参数必须是 Activity,第二个参数则 是RequestCode
ARouter.getInstance().build("/home/main", "ap").navigation(this, 5);

// 直接传递 Bundle
Bundle params = new Bundle();
ARouter.getInstance()
    .build("/home/main")
    .with(params)
    .navigation();

// 指定Flag
ARouter.getInstance()
    .build("/home/main")
    .withFlags();
    .navigation();

// 获取 Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
                    
// 对象传递
ARouter.getInstance()
    .withObject("key", new TestObj("Jack", "Rose"))
    .navigation();

// 觉得接口不够多,可以直接拿出 Bundle  赋值
ARouter.getInstance()
        .build("/home/main")
        .getExtra();

// 转场动画(常规方式)
ARouter.getInstance()
    .build("/test/activity2")
    .withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom)
    .navigation(this);

// 转场动画(API16+)
ActivityOptionsCompat compat = ActivityOptionsCompat.
    makeScaleUpAnimation(v, v.getWidth() / 2, v.getHeight() / 2, 0, 0);

// ps. makeSceneTransitionAnimation 使用共享元素的时候,需要在navigation方法中传入当前Activity

ARouter.getInstance()
    .build("/test/activity2")
    .withOptionsCompat(compat)
    .navigation();
        
// 使用绿色通道(跳过所有的拦截器)
ARouter.getInstance().build("/home/main").greenChannel().navigation();

// 使用自己的日志工具打印日志
ARouter.setLogger();

// 使用自己提供的线程池
ARouter.setExecutor();
  • 更多使用介绍请到官网查看。
3、ARouter 编译时原理分析

ARouter 编译时原理分析

4、ARouter 源码解析
4.1 ARouter 源码主要代码结构
  • arouter-api:上层主要代码,包括入口类 ARouter,主要逻辑代码类 LogisticsCenter,相关辅助类 ClassUtils等。
  • arouter-annotation:ARouter 中主要支持的 annotation(包括 Autowired、Route、Interceptor)的定义,以及 RouteMeta 等基础 model bean 的定义。
  • arouter-compiler:ARouter 中 annotation 对应的 annotation processor 代码,即注解处理器,让这些注解代码起到对应的作用,Arouter 中主要是生成相关代码。(关于 annotation processor,详细了解可参考 Java 注解处理器
  • arouter-gradle-plugin:一个 gradle 插件,目的是在 ARouter 中插入相关注册代码。(代替在 Init 时扫描 dex 文件获取到所有 route 相关类)
  • arouter-idea-plugin: Arouter 的导航插件,帮助两个组件之间关联的代码进行导航。不过目前支持有限,还有一个开源的导航插件,感兴趣的同学可以了解下,ArouterHelperKotlin
4.2 ARouter 初始化流程

ARouter 初始化流程时序图

  • 当我们在 Application 中调用 ARouter.init(this); 进行初始化时:
// ARouter.java
/**
 * init 初始化,必须在使用路由器之前调用
 */
public static void init(Application application) {
  if (!hasInit) {
    logger = _ARouter.logger;
    _ARouter.logger.info(Consts.TAG, "ARouter init start.");
    // 调用 _ARouter 的 init() 方法
    hasInit = _ARouter.init(application);
    // 如果初始化完成后
    if (hasInit) {
      // 获取 InterceptorService 实例
      _ARouter.afterInit();
    }
    _ARouter.logger.info(Consts.TAG, "ARouter init over.");
  }
}
// _ARouter.java
protected static synchronized boolean init(Application application) {
    mContext = application;
    // 调用 LogisticsCenter 的 init() 方法
    LogisticsCenter.init(mContext, executor);
    logger.info(Consts.TAG, "ARouter init success!");
    hasInit = true;
    mHandler = new Handler(Looper.getMainLooper());
    return true;
}

static void afterInit() {
    // 获取 InterceptorService 实例
    interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
}
// LogisticsCenter.java
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
  mContext = context;
  executor = tpe;

  try {
    long startInit = System.currentTimeMillis();
    // 调用 loadRouterMap() 方法
    loadRouterMap();
    if (registerByPlugin) {// 如果通过插件注入,就什么也不做
      logger.info(TAG, "Load router map by arouter-auto-register plugin.");
    } else {// 如果没有通过插件注入,则扫通过描 apk 中的 dex 文件来实现
      Set<String> routerMap;
      // 每次可调试时,它将重建路由器映射
      if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
        logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
        // 这些类是由路由器编译器生成的
        // 通过指定包名 com.alibaba.android.arouter.routes,扫描 dex 文件包下面包含的所有的 ClassName
        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);
      } else {
        logger.info(TAG, "Load router map from cache.");
        routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));
      }

      logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
      startInit = System.currentTimeMillis();
      // 将所有的 Class 文件进行循环并进行分组,然后通过反射的方式构造 Root、Interceptors
      // 、Providers 文件的实例化对象,并将其添加到 Warehouse 仓库中对应的集合里
      for (String className : routerMap) {
        if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
          // 如果 Class 文件是管理模块路由组的 Root 文件,则反射构造 Root 文件的实例化对象,
          // 并且通过 loadInto() 方法将其加入到 Warehouse.groupsIndex 这个 HashMap 集合中来。
          // 注意:这里只是把当前模块下路由组的信息加载到内存当中,但是这一个个路由组的实例化对象,并没有被创建,它们会在被需要的时候才会去实例化。
          ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
          // 同上,加载 Interceptors 文件到 Warehouse.interceptorsIndex 这个 UniqueKeyTreeMap 集合中来。
          ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
        } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
          // 同上,加载 Providers 文件到 Warehouse.providersIndex 这个 HashMap 集合中来。
          ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
        }
      }
    }

    logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");

    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() + "]");
  }
}

/**
 * arouter-auto-register 插件将在此方法中生成代码调用此方法
 * 来注册所有的 Routers、Interceptors、Providers
 */
private static void loadRouterMap() {
    registerByPlugin = false;
    // 通过 gradle 插件自动生成注册码:arouter-auto-register
    // 如下所示:
    // api 生成的 arouter Group
    // register("com.alibaba.android.arouter.routes.ARouter$$Root$$arouterapi");
    // register("com.alibaba.android.arouter.routes.ARouter$$Providers$$arouterapi");
    // module Java 模块
    // register("com.alibaba.android.arouter.routes.ARouter$$Root$$modulejava");
    // register("com.alibaba.android.arouter.routes.ARouter$$Providers$$modulejava");
    // register("com.alibaba.android.arouter.routes.ARouter$$Interceptors$$modulejava");
    // module kotlin 模块
    // register("com.alibaba.android.arouter.routes.ARouter$$Root$$modulekotlin");
    // register("com.alibaba.android.arouter.routes.ARouter$$Providers$$modulekotlin");
}

/**
 * 根据 class name 来注册
 * 牺牲一点效率来解决主 dex 文件过大的问题
 */
private static void register(String className) {
    // 判断类名是否是空
    if (!TextUtils.isEmpty(className)) {
        try {
            // 根据类名获取Class
            Class<?> clazz = Class.forName(className);
            // 创建实例
            Object obj = clazz.getConstructor().newInstance();
            // 将不同的文件分别添加到 Warehouse 仓库对应的集合中去
            if (obj instanceof IRouteRoot) {
                registerRouteRoot((IRouteRoot) obj);
            } else if (obj instanceof IProviderGroup) {
                registerProvider((IProviderGroup) obj);
            } else if (obj instanceof IInterceptorGroup) {
                registerInterceptor((IInterceptorGroup) obj);
            } else {
                logger.info(TAG, "register failed, class name: " + className
                        + " should implements one of IRouteRoot/IProviderGroup/IInterceptorGroup.");
            }
        } catch (Exception e) {
            logger.error(TAG, "register class error:" + className, e);
        }
    }
}
// ClassUtils.java
/**
 * 通过指定包名,扫描包下面包含的所有的ClassName
 *
 * @param context     U know
 * @param packageName 包名
 * @return 所有class的集合
 */
public static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException {
final Set<String> classNames = new HashSet<>();
// 根据传入的 context 获取到当前应用所有的 dex 文件路径集合
List<String> paths = getSourcePaths(context);
// 加入了同步锁,保证 ARouter 先初始化完全
final CountDownLatch parserCtl = new CountDownLatch(paths.size());

for (final String path : paths) {
    DefaultPoolExecutor.getInstance().execute(new Runnable() {
        @Override
        public void run() {
            DexFile dexfile = null;

            try {
                if (path.endsWith(EXTRACTED_SUFFIX)) {
                    //NOT use new DexFile(path), because it will throw "permission error in /data/dalvik-cache"
                    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);
                    }
                }
            } catch (Throwable ignore) {
                Log.e("ARouter", "Scan map file in dex files made error.", ignore);
            } finally {
                if (null != dexfile) {
                    try {
                        dexfile.close();
                    } catch (Throwable ignore) {
                    }
                }

                parserCtl.countDown();
            }
        }
    });
}

parserCtl.await();

Log.d(Consts.TAG, "Filter " + classNames.size() + " classes by packageName <" + packageName + ">");
return classNames;
}
// Warehouse.java
/**
 * Warehouse 数据存储仓库
 */
class Warehouse {
    // 路由组集合,key 为组名,value 为路由组的 Class(HashMap)
    static Map<String, Class<? extends IRouteGroup>> groupsIndex = new HashMap<>();
    // 路由组按需加载完成后,存放到路由集合中(HashMap)
    static Map<String, RouteMeta> routes = new HashMap<>();

    // 每个服务的原始信息加载完成后存放到这里(HashMap)
    static Map<String, RouteMeta> providersIndex = new HashMap<>();
    // 服务集合,key 为服务的 Class,value 为服务的实例,需要时才会创建实例(HashMap)
    static Map<Class, IProvider> providers = new HashMap<>();

    // 拦截器的集合 (TreeMap)
    static Map<Integer, Class<? extends IInterceptor>> interceptorsIndex = new UniqueKeyTreeMap<>("More than one interceptors use same priority [%s]");
    // 拦截器按需加载完成后,存放到该拦截器集合中(ArrayList)
    static List<IInterceptor> interceptors = new ArrayList<>();

    /**
     * 清除所有集合的数据
     */
    static void clear() {
        routes.clear();
        groupsIndex.clear();
        providers.clear();
        providersIndex.clear();
        interceptors.clear();
        interceptorsIndex.clear();
    }
}
4.3 ARouter 路由跳转流程
  • 当我们调用ARouter.getInstance().build("/home/main").navigation();进行路由跳转时:
    ARouter 路由跳转流程时序图
// ARouter.java
public Postcard build(String path) {
  return _ARouter.getInstance().build(path);
}

@Deprecated
public Postcard build(String path, String group) {
  return _ARouter.getInstance().build(path, group, false);
}

public Postcard build(Uri url) {
  return _ARouter.getInstance().build(url);
}
// _ARouter.java
/**
 * 根据 path 构建一个 Postcard 对象
 */
protected Postcard build(String path) {
  if (TextUtils.isEmpty(path)) {
    throw new HandlerException(Consts.TAG + "Parameter is invalid!");
  } else {
    // 获取 PathReplaceService 服务,对外提供修改路由 path 和 uri(只需要重写该类)
    PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
    if (null != pService) {
      path = pService.forString(path);
    }
    return build(path, extractGroup(path), true);
  }
}

/**
 * 根据 uri 构建一个 Postcard 对象
 */
protected Postcard build(Uri uri) {
  if (null == uri || TextUtils.isEmpty(uri.toString())) {
    throw new HandlerException(Consts.TAG + "Parameter invalid!");
  } else {
    // 获取 PathReplaceService 服务,对外提供修改路由 path 和 uri(只需要重写该类)
    PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
    if (null != pService) {
      uri = pService.forUri(uri);
    }
    // 创建一个 Postcard 对象
    return new Postcard(uri.getPath(), extractGroup(uri.getPath()), uri, null);
  }
}

/**
 * 根据 path 和 group 构建一个 Postcard 对象
 */
protected Postcard build(String path, String group, Boolean afterReplace) {
  if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
    throw new HandlerException(Consts.TAG + "Parameter is invalid!");
  } else {
    if (!afterReplace) {
      // 获取 PathReplaceService 服务,对外提供修改路由 path 和 uri(只需要重写该类)
      PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
      if (null != pService) {
        path = pService.forString(path);
      }
    }
    // 创建一个 Postcard 对象
    return new Postcard(path, group);
  }
}

/**
 * 根据路径获取 Group
 */
private String extractGroup(String path) {
  // 如果不是以/开头,编译期可以通过编译只是不创建对应的类
  // 如果是空或者不是以/开头 则直接抛出异常
  if (TextUtils.isEmpty(path) || !path.startsWith("/")) {
    throw new HandlerException(Consts.TAG + "Extract the default group failed, the path must be start with '/' and contain more than 2 '/'!");
  }

  try {
    String defaultGroup = path.substring(1, path.indexOf("/", 1));
    if (TextUtils.isEmpty(defaultGroup)) {
      throw new HandlerException(Consts.TAG + "Extract the default group failed! There's nothing between 2 '/'!");
    } else {
      return defaultGroup;
    }
  } catch (Exception e) {
    logger.warning(Consts.TAG, "Failed to extract default group! " + e.getMessage());
    return null;
  }
}

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
  // 获取 PretreatmentService 路由预处理服务,对外提供修改路由能力
  PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);
  if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {
    // Pretreatment failed, navigation canceled.
    return null;
  }

  // Set context to postcard.
  postcard.setContext(null == context ? mContext : context);

  try {// 执行 completion
    // 填充 postcard
    LogisticsCenter.completion(postcard);
  } catch (NoRouteFoundException ex) {
    logger.warning(Consts.TAG, ex.getMessage());

    if (debuggable()) {
      // Show friendly tips for user.
      runInMainThread(new Runnable() {
        @Override
        public void run() {
          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.
      // 如果上一步发送错误,且没有 callback 回调
      // 获取 DegradeService 全局降级服务,对外提供修改路由能力,出错策略自定义的机会
      DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
      if (null != degradeService) {
        degradeService.onLost(context, postcard);
      }
    }

    return null;
  }

  if (null != callback) {// 执行成功回调
    callback.onFound(postcard);
  }
  // Provider 和 Fragment 不走拦截器
  if (!postcard.isGreenChannel()) {// 必须在异步线程中运行,也许拦截器花费太多时间导致 ANR。
    // 执行拦截器的 doInterceptions() 方法
    interceptorService.doInterceptions(postcard, new InterceptorCallback() {
      /**
       * Continue process 没有中断的回调
       *
       * @param postcard route meta
       */
      @Override
      public void onContinue(Postcard postcard) {
        // 如果没有中断最终将执行该方法
        _navigation(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(postcard, requestCode, callback);
  }
  return null;
}
// LogisticsCenter.java
public synchronized static void completion(Postcard postcard) {
  if (null == postcard) {
    throw new NoRouteFoundException(TAG + "No postcard!");
  }
  // 根据路径查看当前已经按组加载过的 RouteMeta 是否在内存中存在,从而获取 RouteMeta
  RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
  if (null == routeMeta) {// 首次调用 routeMeta 为 null
    // 如果 map 中不包含 postcard 的 group 则抛出异常
    if (!Warehouse.groupsIndex.containsKey(postcard.getGroup())) {
      throw new NoRouteFoundException(TAG + "There is no route match the path [" + postcard.getPath() + "], in group [" + postcard.getGroup() + "]");
    } else {
      // 加载路由并将其缓存到内存中,然后从元数据中删除
      try {
        if (ARouter.debuggable()) {
          logger.debug(TAG, String.format(Locale.getDefault(), "The group [%s] starts loading, trigger by [%s]", postcard.getGroup(), postcard.getPath()));
        }
        // 将属于这个 group 中的所有路由都添加到 map 中
        addRouteGroupDynamic(postcard.getGroup(), null);

        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() 方法
      completion(postcard);
    }
  } 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:// 如果是 Provider 类型,应该找到它的实例
        // 如果是 Provider 必须实现 IProvider 接口
        // 创建 Provider 实例
        Class<? extends IProvider> providerMeta = (Class<? extends IProvider>) routeMeta.getDestination();
        // 从缓存中获取 Provider
        IProvider instance = Warehouse.providers.get(providerMeta);
        if (null == instance) {
          IProvider provider;
          try {// 如果为空,通过反射的方式创建 IProvider
            provider = providerMeta.getConstructor().newInstance();
            provider.init(mContext);
            Warehouse.providers.put(providerMeta, provider);
            instance = provider;
          } catch (Exception e) {
            logger.error(TAG, "Init provider failed!", e);
            throw new HandlerException("Init provider failed!");
          }
        }
        postcard.setProvider(instance);
        postcard.greenChannel();// 默认 Provider 和 Fragment 不走拦截器
        break;
      case FRAGMENT:
        postcard.greenChannel();// 默认 Provider 和 Fragment 不走拦截器
      default:
        break;
    }
  }
}
// _ARouter.java
private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {
  final Context currentContext = postcard.getContext();

  switch (postcard.getType()) {
    case ACTIVITY:// 目标页是 Activity
      // Build intent 创建 Intent
      final Intent intent = new Intent(currentContext, postcard.getDestination());
      // 设置 Intent 参数
      intent.putExtras(postcard.getExtras());
      // 设置 Activity 的 flags
      int flags = postcard.getFlags();
      if (0 != flags) {
        intent.setFlags(flags);
      }

      // 如果 currentContext 为 Application 的 Context,
      // 那么将当前 Activity 的 flags 设置为 FLAG_ACTIVITY_NEW_TASK,
      // 即新启动一个栈空间
      if (!(currentContext instanceof Activity)) {
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      }

      // 设置 Actions
      String action = postcard.getAction();
      if (!TextUtils.isEmpty(action)) {
        intent.setAction(action);
      }

      // 最终在主线程中调用 startActivitu() 方法
      runInMainThread(new Runnable() {
        @Override
        public void run() {
          startActivity(requestCode, currentContext, intent, postcard, callback);
        }
      });

      break;
    case PROVIDER:// 目标页是 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;
}
4.4 ARouter 参数的传入与获取流程
  • (1)当我们调用withString("name", "张三")或者withXXX("xxx", xxx)方法进行参数传入时:
    ARouter 参数传入流程时序图
// Postcard.java
private Bundle mBundle;

public void navigation(Activity mContext, int requestCode, NavigationCallback callback) {
    ARouter.getInstance().navigation(mContext, this, requestCode, callback);
}

public Postcard withString(@Nullable String key, @Nullable String value) {
    mBundle.putString(key, value);
    return this;
}

public Postcard withBoolean(@Nullable String key, boolean value) {
    mBundle.putBoolean(key, value);
    return this;
}
...
// 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) {
    ...
    try {
        LogisticsCenter.completion(postcard);
    } catch (NoRouteFoundException ex) {
    ...
}
// LogisticsCenter.java
public synchronized static void completion(Postcard postcard) {
    ...
    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[]{}));
    }
    ...
}

private static void setValue(Postcard postcard, Integer typeDef, String key, String value) {
    if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {
        return;
    }

    try {
        if (null != typeDef) {
            if (typeDef == TypeKind.BOOLEAN.ordinal()) {
                postcard.withBoolean(key, Boolean.parseBoolean(value));
            } else if (typeDef == TypeKind.BYTE.ordinal()) {
                postcard.withByte(key, Byte.parseByte(value));
            } else if (typeDef == TypeKind.SHORT.ordinal()) {
                postcard.withShort(key, Short.parseShort(value));
            } else if (typeDef == TypeKind.INT.ordinal()) {
                postcard.withInt(key, Integer.parseInt(value));
            } else if (typeDef == TypeKind.LONG.ordinal()) {
                postcard.withLong(key, Long.parseLong(value));
            } else if (typeDef == TypeKind.FLOAT.ordinal()) {
                postcard.withFloat(key, Float.parseFloat(value));
            } else if (typeDef == TypeKind.DOUBLE.ordinal()) {
                postcard.withDouble(key, Double.parseDouble(value));
            } else if (typeDef == TypeKind.STRING.ordinal()) {
                postcard.withString(key, value);
            } else if (typeDef == TypeKind.PARCELABLE.ordinal()) {
                // TODO : How to description parcelable value with string?
            } else if (typeDef == TypeKind.OBJECT.ordinal()) {
                postcard.withString(key, value);
            } else {    // Compatible compiler sdk 1.0.3, in that version, the string type = 18
                postcard.withString(key, value);
            }
        } else {
            postcard.withString(key, value);
        }
    } catch (Throwable ex) {
        logger.warning(Consts.TAG, "LogisticsCenter setValue failed! " + ex.getMessage());
    }
}
  • 其最终的参数是传递到了 Postcard 类中的 mBundle 中。
  • (2)当我们在ActivityonCreate()方法中调用ARouter.getInstance().inject(this)注入参数和服务,通过@Autowired标记注解@Autowired @JvmField var name: String? = null,通过上述两者进行参数获取时:
    ARouter 参数获取流程时序图
// _ARouter.java
static void inject(Object thiz) {
    // 获取 AutowiredService
    AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
    if (null != autowiredService) {
        autowiredService.autowire(thiz);
    }
}
// AutowiredServiceImpl.java
 @Override
public void autowire(Object instance) {
    doInject(instance, null);
}

/**
 * 递归注入
 *
 * @param instance who call me.
 * @param parent   parent of me.
 */
private void doInject(Object instance, Class<?> parent) {
    Class<?> clazz = null == parent ? instance.getClass() : parent;

    ISyringe syringe = getSyringe(clazz);
    if (null != syringe) {
        // 调用辅助类的 inject 方法
        syringe.inject(instance);
    }
    // 获取父类
    Class<?> superClazz = clazz.getSuperclass();
    // 父类不为空,且不是 framework 的类
    if (null != superClazz && !superClazz.getName().startsWith("android")) {
        doInject(instance, superClazz);
    }
}

/**
 * 获取注解生成的辅助类
 *
 * @param clazz Class<?>
 * @return ISyringe
 */
private ISyringe getSyringe(Class<?> clazz) {
    String className = clazz.getName();

    try {
        if (!blackList.contains(className)) {
            ISyringe syringeHelper = classCache.get(className);
            if (null == syringeHelper) {  // No cache.
                // 类名$$ARouter$$Autowired(例如:KotlinTestActivity$$ARouter$$Autowired),反射
                syringeHelper = (ISyringe) Class.forName(clazz.getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
            }
            classCache.put(className, syringeHelper);
            return syringeHelper;
        }
    } catch (Exception e) {
        blackList.add(className);    // This instance need not autowired.
    }

    return null;
}
// 生成的 KotlinTestActivity 辅助类
public class KotlinTestActivity$$ARouter$$Autowired implements ISyringe {
  private SerializationService serializationService;

  @Override
  public void inject(Object target) {
    serializationService = ARouter.getInstance().navigation(SerializationService.class);
    KotlinTestActivity substitute = (KotlinTestActivity)target;
    //调用 KotlinTestActivity 的 getIntent() 获取参数
    substitute.name = substitute.getIntent().getStringExtra("name");
    substitute.age = substitute.getIntent().getIntExtra("age", substitute.age);
  }
}
5、不同类型的 IProvider 实现
5.1 PathReplaceService 接口实现
/**
 * PathReplaceServiceImpl
 *
 * @Description: 跳转前第一次预处理
 *               实现 PathReplaceService 接口,并必须加以 @Route 注解
 *               path 地址只要保证正常的格式,内容是什么好像无所谓
 *               一般我们会使用 @Route(path = "/pathReplace/service") 为默认地址
 */
@Route(path = "/pathReplace/service")
class PathReplaceServiceImpl : PathReplaceService {

    private var context: Context? = null

    override fun init(context: Context?) {
        this.context = context
    }

    override fun forString(path: String): String {
        Log.d("PathReplaceServiceImpl", "forString: $path")
        return path
    }

    override fun forUri(uri: Uri): Uri {
        Log.d("PathReplaceServiceImpl", "forUri: $uri")
        return uri
    }
}
5.2 PretreatmentService 接口实现
/**
 * PretreatmentServiceImpl
 *
 * @Description: 跳转前第二次预处理
 *               实现 PretreatmentService 接口,并必须加以 @Route 注解
 *               path 地址只要保证正常的格式,内容是什么好像无所谓
 *               一般我们会使用 @Route(path = "/pretreatment/service") 为默认地址
 */
@Route(path = "/pretreatment/service")
class PretreatmentServiceImpl : PretreatmentService {

    private var context: Context? = null

    override fun init(context: Context?) {
        this.context = context
    }

    override fun onPretreatment(context: Context?, postcard: Postcard): Boolean {
        this.context = context
        // 跳转前预处理,如果需要自行跳转,该方法返回 false 即可
        Log.d("PretreatmentServiceImpl", "onPretreatment: $postcard")
        return true
    }
}
5.3 DegradeService 接口实现
/**
 * DegradeServiceImpl
 *
 * @Description: 全局降级服务(当参数跳转错误时)
 *               path 地址只要保证正常的格式,内容是什么好像无所谓
 *               一般我们会使用 @Route(path = "/degradeService/service") 为默认地址
 */
@Route(path = "/degradeService/service")
class DegradeServiceImpl : DegradeService {

    private var context: Context? = null

    override fun init(context: Context?) {
        this.context = context
    }

    override fun onLost(context: Context?, postcard: Postcard?) {
        Log.d("DegradeServiceImpl", "onLost: $postcard")
    }
}
6、总结
  • 初始化:ARouter 的路由、参数和拦截器都是通过注解来标注的,然后通过注解生成器分别生成不同的路由表,当我们在 Application 调用 ARouter 的 init() 方法进行初始化时,最终会调用 LogisticsCenter 的 init(xxx) 方法,默认通过反射加载这些路由表信息,并最终归类到 Warehouse 这个类中的不同集合里面进行存储。
  • 路由跳转:当我们调用 ARouter 的 build() 方法后,首先会获取一个路径替换服务,从而对外提供对路径修改等操作,接着根据路径生成一个 Postcard 对象,然后在调用 Postcard 的 navigation() 方法时,最终调用 _ARouter 的 navigation() 方法,在这个方法中,首先会处理预处理服务,然后调用 LogisticsCenter 的 completion(xxx) 方法填充 Postcard 中的信息,如果 LogisticsCenter 没有找到对应的路由信息的话,就会走降级策越,如果找到对应的路由信息,就判断是不是走绿色通道,所谓的绿色通道就是 Provider 和 Fragment 不走拦截器的一个方法,如果不走绿色通道,就交给拦截器链决定是否跳转或如何跳转,如果走绿色通道,就直接按照 Activit 和 Fragment 等不同类型进行跳转或实例化返回。
  • 参数传入 当我们通过 withXxx(xxx) 方法进行参数传入的时,其实就是在 build() 出一个 Postcard 对象后,然后调用 LogisticsCenter 的 setValue() 方法将其需要传入的参数最终存入 Postcard 中的 Bundle 里面。
  • 参数获取 当我们在 Activity 中调用 ARouter 的 inject(this) 方法去注入参数和服务时,其实就是通过对 @Autowirte 注解标记的变量,让其丢给 AutowiredService 的 doInject() 方法进行递归注入,最终还是通过 Activity 的 getIntent() 去进行参数获取。
  • ARouter 加载路由表信息有两种方式,一种是运行时反射,另外一种是编译时插入,默认为运行时反射。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值