美文网首页Android干货
ARouter使用方式及源码学习

ARouter使用方式及源码学习

作者: Bernardo_Silva | 来源:发表于2019-04-05 11:29 被阅读0次

    使用前配置

    1. 在每个module的build.gradle添加如下代码,作用是为注解执行器提供module的名称
        defaultConfig {
            ...
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = [AROUTER_MODULE_NAME: project.getName()]
                }
            }
        }
    
    1. 添加依赖
    dependencies {
        api ''com.alibaba:arouter-api:1.4.1'
        annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'
        ...
    }
    
    1. 在Application初始化
    if (isDebug()) {         
        ARouter.openLog(); 
        ARouter.openDebug();
    }
    ARouter.init(mApplication);
    
    1. 在需要使用的类声明注解
    @Route(path = "/test/activity")
    public class YourActivity extend Activity {
        ...
    }
    
    1. 调用api
    // 1. Simple jump within application (Jump via URL in 'Advanced usage')
    ARouter.getInstance().build("/test/activity").navigation();
    
    // 2. Jump with parameters
    ARouter.getInstance().build("/test/1")
                .withLong("key1", 666L)
                .withString("key3", "888")
                .withObject("key4", new Test("Jack", "Rose"))
                .navigation();
    // 3. with Bundle
    Bundle bundle= new Bundle();
    ARouter.getInstance()
              .build("/test/1")
              .with(bundle)
              .navigation();
    // 4. with Parcelable
    public class LoginAction implements Parcelable {
    }
    @Route(path = ROUTE_LOGIN)
    public class LoginActivity {
        @Autowired(name = Constants.INTENT_KEY_LOGIN_ACTION)
        public LoginAction loginAction;
    }
    ARouter.getInstance()
                        .build(ROUTE_LOGIN)
                        .withParcelable(Constants.INTENT_KEY_LOGIN_ACTION, loginAction)
                        .navigation();
    

    注意:在工程的主module里需要依赖其他所有module,否则会找不到路由

    额外一些使用

    • 自定义Provider服务
    // 1. 继承IProvider接口
    public interface MyService extends IProvider {
        String doSomething();
    }
    // 2. 实现MyService接口,加上注解
    @Route(path = "/myservice/xxx")
    public class MyServiceImpl implements MyService {
        @Override
        public void init(Context context) {
        }
    
        @Override
        public String doSomething() {
            return "haha";
        }
    }
    
    • 获取Provider服务的方法
    // 1. 通过路径获取
    ARouter.getInstance().build("/myservice/xxx").navigation()
    // 2. 通过类名获取
    ARouter.getInstance().navigation(MyService.class)
    
    • 跳转动画(api >= 16)
    ActivityOptionsCompat compat = ActivityOptionsCompat.makeCustomAnimation(this,
                R.anim.translate_in, R.anim.translate_none);
    
    ARouter.getInstance()
               .build("/test/activity")
               .withOptionsCompat(compat)
               .navigation();
    
    • 跳转携带参数不常用的一种,原理是将实体类转换成json字符串,通过String的方式进行传递
    // 首先需要实现SerializationService
    @Route(path = "/serializationservice/s1")
    public class SerializationServiceIpml implements SerializationService {
        @Deprecated
        @Override
        public <T> T json2Object(String input, Class<T> clazz) {
            return null;
        }
    
        @Override
        public String object2Json(Object instance) {
            return null;
        }
    
        @Override
        public <T> T parseObject(String input, Type clazz) {
            return null;
        }
    
        @Override
        public void init(Context context) {
    
        }
    }
    ARouter.getInstance()
                        .build("/test/1")
                        .withObject("key_bean", bean)
                        .navigation();
    
    • 全局的降级策略
    @Route(path = "/degradeservice/d1")
    public class DegradeServiceImpl implements DegradeService {
        private static final String TAG = "DegradeServiceImpl";
        @Override
        public void onLost(Context context, Postcard postcard) {
            // do something.
            Log.d(TAG, "DegradeService##onLost");
        }
    
        @Override
        public void init(Context context) {
            Log.d(TAG, "DegradeService##init");
        }
    }
    
    • 实现路径转换
    @Route(path = "/pathservice/p1")
    public class PathReplaceServiceImpl implements PathReplaceService {
        private static final String TAG = "PathReplaceServiceImpl";
        @Override
        public void init(Context context) {
            Log.d(TAG, "PathReplaceService##init");
        }
    
        @Override
        public String forString(String path) {
            Log.d(TAG, "PathReplaceService##forString");
            return path;
        }
    
        @Override
        public Uri forUri(Uri uri) {
            Log.d(TAG, "PathReplaceService##forUri");
            return uri;
        }
    }
    
    • 使用带回调的跳转
    ARouter.getInstance().build("/test/test1").navigation(this, new NavCallback() {
                    @Override
                    public void onFound(Postcard postcard) {
                         // 
                    }
    
                    @Override
                    public void onLost(Postcard postcard) {
                        // 找不到路径对应的目标
                    }
    
                    @Override
                    public void onArrival(Postcard postcard) {
                        // 跳转完成
                    }
    
                    @Override
                    public void onInterrupt(Postcard postcard) {
                        // 被拦截了,Important! 该方法运行在子线程
                    }
                });
    
    • 使用拦截器,priority值越小,优先级越高,值不能定义一样的
    @Interceptor(priority = 5)
    public class Test1Interceptor implements IInterceptor {
        @Override
        public void process(Postcard postcard, InterceptorCallback callback) {
           // process方法运行在子线程
           //在此方法中如果没有调用以下两个方法其中之一,那么不再执行后续的拦截器
           //需等待300s(默认值,可设置改变)的时间,才能抛出拦截器中断
           callback.onContinue(postcard);
           callback.onInterrupt(exception)
        }
    
        @Override
        public void init(Context context) {
           // 拦截器的初始化发生在跳转之前
        }
    }
    

    源码分析

    ARouter提供了两个SDK,分别是面向两个不同的阶段。API这个SDK是面向运行期的,而Compiler这个SDK则是作用于编译期的。

    一、 注解执行器生成java代码

    此阶段发生在编译期,主要是通过自定义的注解执行器对代码中的@Route、@Autowired和@Interceptor这三个注解进行解析,生成java文件。具体的细节请看这篇文章 阿里ARouter使用及源码解析,注解执行器的使用看这篇文章 Android编译时注解APT实战

    编译生成的文件路径和文件内容如下:


    文件路径和文件名
    public class ARouter$$Group$$mylibrary implements IRouteGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> atlas) {
        atlas.put("/mylibrary/MyLibActivity", RouteMeta.build(RouteType.ACTIVITY, MyLibActivity.class, 
        "/mylibrary/mylibactivity", "mylibrary", new java.util.HashMap<String, Integer>(){{
         put("name", 8); }}, -1, -2147483648));
      }
    }
    
    public class ARouter$$Providers$$mylibrary implements IProviderGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> providers) {
      }
    }
    
    public class ARouter$$Root$$mylibrary implements IRouteRoot {
      @Override
      public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
        routes.put("mylibrary", ARouter$$Group$$mylibrary.class);
      }
    }
    
    public class MyLibActivity$$ARouter$$Autowired implements ISyringe {
      private SerializationService serializationService;
    
      @Override
      public void inject(Object target) {
        serializationService = ARouter.getInstance().navigation(SerializationService.class);
        MyLibActivity substitute = (MyLibActivity)target;
        substitute.name = substitute.getIntent().getStringExtra("name");
      }
    }
    
    public class ARouter$$Interceptors$$common implements IInterceptorGroup {
      @Override
      public void loadInto(Map<Integer, Class<? extends IInterceptor>> interceptors) {
        interceptors.put(5, Test1Interceptor.class);
      }
    }
    
    

    二、 应用启动时初始化

    // Application的onCreate方法中调用
    ARouter.init(this);
     
    public static void init(Application application) {
           if (!hasInit) {
               // 步骤1
               hasInit = _ARouter.init(application);
               if (hasInit) {
                   // 步骤2
                   _ARouter.afterInit();
               }
           }
     }
    
    1. 步骤1主要是将自动生成的类加载进内存仓库

    ARouter 仅载入了 Group 清单,并没有具体载入每个 Group 中包含的具体的路由节点清单,只有当使用到具体的 Group 时,才会加载对应的 Group 列表

    首先判断是否使用了插件来获取“com.alibaba.android.arouter.routes”这个包底下的类名信息,如果没有的话需要扫描dex文件来获取这些信息。

    // _ARouter的init方法
    // 创建了一个核心数和最大数都为cpu+1的线程池,队列为64
    protected static synchronized boolean init(Application application) {
            mContext = application;
            // 主要方法
            LogisticsCenter.init(mContext, executor);
            hasInit = true;
            mHandler = new Handler(Looper.getMainLooper());
            return true;
    }
    
    // LogisticsCenter的init方法
    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
            mContext = context;
            executor = tpe;
    
            try {
                // 判断是否用插件扫描加载类信息
                if (registerByPlugin) {
                    logger.info(TAG, "Load router map by arouter-auto-register plugin.");
                } else {
                    Set<String> routerMap;
    
                    // It will rebuild router map every times when debuggable.
                    if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
                        logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
                        // 扫描dex
                        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>()));
                    }
    
                    logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");
                    startInit = System.currentTimeMillis();
                    // 反射生成对应的类,保存到内存仓库
                    for (String className : routerMap) {
                        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);
                        }
                    }
                }
            } catch (Exception e) {
                throw new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");
            }
        }
    
    2. 步骤2主要是初始化拦截器
      // _ARouter的afterInit方法
      static void afterInit() {
            interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();
        }
    

    此处初始化拦截器的方法和第三步要分析的调用过程是同一个,所以放一起分析。

    三、调用过程分析

    调用方法如下:

    ARouter.getInstance().build("/arouter/service/interceptor").navigation();

    1. ARouter.getInstance().build("/arouter/service/interceptor")最终会调用到_ARouter中的build方法
     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));
            }
        }
    
        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);
                }
                return new Postcard(path, group);
            }
        }
    
    public final class Postcard extends RouteMeta {
        // Base
        private Uri uri;
        private Object tag;             // A tag prepare for some thing wrong.
        private Bundle mBundle;         // Data to transform
        private int flags = -1;         // Flags of route
        private int timeout = 300;      // Navigation timeout, TimeUnit.Second
        private IProvider provider;     // It will be set value, if this postcard was provider.
        private boolean greenChannel;
        private SerializationService serializationService;
        // Animation
        private Bundle optionsCompat;    // The transition animation of activity
        private int enterAnim = -1;
        private int exitAnim = -1;
    }
    
    
    

    这里主要做的事情就是生成一个Postcard对象,根据路径截取group名称,保存在里面。Postcard是RouteMeta的子类,保存了跳转时相关的信息。此处可以看到,如果我们实现了PathReplaceService,会调用forString方法进行转换path

    2. 拿到Postcard对象之后调用navigation,最终调用的是_ARouter的navigation方法,如下
    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            try {
                // 方法1
                LogisticsCenter.completion(postcard);
            } catch (NoRouteFoundException ex) {
                // 如果抛异常了,有设置回调的话,调用回调的onLost
                if (null != callback) {
                    callback.onLost(postcard);
                } else {  
                // 如果没有设置回调,则调用全局的降级策略,需要自己实现
                    DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);
                    if (null != degradeService) {
                        degradeService.onLost(context, postcard);
                    }
                }
    
                return null;
            }
    
            // 没有抛异常,有设置回调的话,调用回调的onFound
            if (null != callback) {
                callback.onFound(postcard);
            }
    
            // 判断是否需要经过拦截器
            if (!postcard.isGreenChannel()) {
                // 关键方法3
                interceptorService.doInterceptions(postcard, new InterceptorCallback() {
                
                    @Override
                    public void onContinue(Postcard postcard) {
                       // 关键方法2
                        _navigation(context, postcard, requestCode, callback);
                    }
    
                    @Override
                    public void onInterrupt(Throwable exception) {
                        if (null != callback) {
                            // 被拦截器拦截了,有设置回调的话,调用回调的onInterrupt
                            callback.onInterrupt(postcard);
                        }
                    }
                });
            } else {
                // 关键方法2,不管经不经过拦截器,最终都调用此方法
                return _navigation(context, postcard, requestCode, callback);
            }
    
            return null;
        }
    
    1. 首先我们看关键方法1
    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;
                }
            }
        }
    

    此方法首先判断内存仓库Warehouse里面是否已经有该路径对应的RouteMeta,如果没有则调用自动生成的IRouteGroup的loadInto方法加载进来,然后通过RouteMeta对postcard对象赋值。此外可以看到,IProvider和Fragment是不需要经过拦截器的。

    2. 接着我们看关键方法2
       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;
        }
    
    // startActivity方法
    private void startActivity(int requestCode, Context currentContext, Intent intent, Postcard postcard, NavigationCallback callback) {
           if (requestCode >= 0) {  // Need start for result
                if (currentContext instanceof Activity) {
                    ActivityCompat.startActivityForResult((Activity) currentContext, intent, requestCode, postcard.getOptionsBundle());
                } else {
                    logger.warning(Consts.TAG, "Must use [navigation(activity, ...)] to support [startActivityForResult]");
                }
            } else {
                ActivityCompat.startActivity(currentContext, intent, postcard.getOptionsBundle());
            }
    
            if ((-1 != postcard.getEnterAnim() && -1 != postcard.getExitAnim()) && currentContext instanceof Activity) {    // Old version.
                ((Activity) currentContext).overridePendingTransition(postcard.getEnterAnim(), postcard.getExitAnim());
            }
            // 跳转之后,如果有设置回调,调用onArrival
            if (null != callback) {
                callback.onArrival(postcard);
            }
        }
    

    此方法比较简单,就是根据不同的类型做不同的事情,Activity的话就执行startActivity跳转,如果是Fragment的话就返回Fragment对象,如果是IProvider的话就返回IProvider对象。

    3. 最后我们看关键方法3
          if (!postcard.isGreenChannel()) {
                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());
                    }
                });
          }
    
    

    interceptorService是InterceptorServiceImpl对象,是在ARouter初始化时,调用_ARouter的afterInit方法创建的,即ARouter.getInstance().build("/arouter/service/interceptor").navigation();
    这个方法的流程在上面关键方法1我们已经分析过了,它主要是初始化了InterceptorServiceImpl对象,并调用了init方法

    case PROVIDER:
            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;
    

    下面看看InterceptorServiceImpl对象init方法

        @Override
        public void init(final Context context) {
            LogisticsCenter.executor.execute(new Runnable() {
                @Override
                public void run() {
                    if (MapUtils.isNotEmpty(Warehouse.interceptorsIndex)) {
                        for (Map.Entry<Integer, Class<? extends IInterceptor>> entry : Warehouse.interceptorsIndex.entrySet()) {
                            Class<? extends IInterceptor> interceptorClass = entry.getValue();
                            try {
                                IInterceptor iInterceptor = interceptorClass.getConstructor().newInstance();
                                iInterceptor.init(context);
                                Warehouse.interceptors.add(iInterceptor);
                            } catch (Exception ex) {
                                throw new HandlerException(TAG + "ARouter init interceptor error! name = [" + interceptorClass.getName() + "], reason = [" + ex.getMessage() + "]");
                            }
                        }
    
                        interceptorHasInit = true;
    
                        logger.info(TAG, "ARouter interceptors init over.");
    
                        synchronized (interceptorInitLock) {
                            interceptorInitLock.notifyAll();
                        }
                    }
                }
            });
        }
    

    此方法主要是按照优先级顺序生成所有拦截器对象,并调用拦截器的init方法,是在线程池中操作的,所有init执行完之后会将标志位置为true,interceptorHasInit = true;

    接着看看interceptorService的doInterceptions方法

        @Override
        public void doInterceptions(final Postcard postcard, final InterceptorCallback callback) {
            if (null != Warehouse.interceptors && Warehouse.interceptors.size() > 0) {
                // 第一步先检查是否所有拦截器都执行完init方法
                checkInterceptorsInitStatus();
    
                if (!interceptorHasInit) {
                    callback.onInterrupt(new HandlerException("Interceptors initialization takes too much time."));
                    return;
                }
                // 第二步在线程池中执行拦截器的process方法
                LogisticsCenter.executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        CancelableCountDownLatch interceptorCounter = new CancelableCountDownLatch(Warehouse.interceptors.size());
                        try {
                            // 关键方法
                            _excute(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()) {
                                // 在拦截器中我们可以给postcard设置tag,如果tag不为null,最终会走我们设置的callback的onInterrupt,tag一般用来设置异常
                                callback.onInterrupt(new HandlerException(postcard.getTag().toString()));
                            } else {
                                callback.onContinue(postcard);
                            }
                        } catch (Exception e) {
                            callback.onInterrupt(e);
                        }
                    }
                });
            } else {
                // 没有拦截器
                callback.onContinue(postcard);
            }
        }
    
       private static void checkInterceptorsInitStatus() {
            synchronized (interceptorInitLock) {
                while (!interceptorHasInit) {
                    try {
                        interceptorInitLock.wait(10 * 1000);
                    } catch (InterruptedException e) {
                        throw new HandlerException(TAG + "Interceptor init cost too much time error! reason = [" + e.getMessage() + "]");
                    }
                }
            }
        }
    

    我们看看关键方法_excute

      private static void _excute(final int index, final CancelableCountDownLatch counter, final Postcard postcard) {
            if (index < Warehouse.interceptors.size()) {
                IInterceptor iInterceptor = Warehouse.interceptors.get(index);
                iInterceptor.process(postcard, new InterceptorCallback() {
                    @Override
                    public void onContinue(Postcard postcard) {
                        // Last interceptor excute over with no exception.
                        counter.countDown();
                        _excute(index + 1, counter, postcard);  
                    }
    
                    @Override
                    public void onInterrupt(Throwable exception) {
                        postcard.setTag(null == exception ? new HandlerException("No message.") : exception.getMessage());  
                        counter.cancel();
    
                    }
                });
            }
        }
    

    可以看到,这个方法主要是逐一取出拦截器,并执行process方法,在此方法中我们需要调用 callback.onContinue(postcard);或者callback.onInterrupt(exception);

    四、 分析传值的过程

    传值的方法在上面api使用已经介绍过,在相应的界面,我们可以通过注解和调用inject方法来获取相应的值

     @Autowired
     public String name;
    
     ARouter.getInstance().inject(this);
    

    传值的过程比较简单,注解执行器在编译阶段会将@Autowired注解生成对应的文件。

    public class MyLibActivity$$ARouter$$Autowired implements ISyringe {
      private SerializationService serializationService;
    
      @Override
      public void inject(Object target) {
        serializationService = ARouter.getInstance().navigation(SerializationService.class);
        MyLibActivity substitute = (MyLibActivity)target;
        substitute.name = substitute.getIntent().getStringExtra("name");
      }
    }
    

    当你调用ARouter.getInstance().inject(this)时,根据类名取出相应的ISyringe对象,该对象就是上面所说自动生成的类的对象

      static void inject(Object thiz) {
            AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
            if (null != autowiredService) {
                autowiredService.autowire(thiz);
            }
       }
    
        @Override
        public void autowire(Object instance) {
            String className = instance.getClass().getName();
            try {
                if (!blackList.contains(className)) {
                    ISyringe autowiredHelper = classCache.get(className);
                    if (null == autowiredHelper) {  // No cache.
                        autowiredHelper = (ISyringe) Class.forName(instance.getClass().getName() + SUFFIX_AUTOWIRED).getConstructor().newInstance();
                    }
                    autowiredHelper.inject(instance);
                    classCache.put(className, autowiredHelper);
                }
            } catch (Exception ex) {
                blackList.add(className);    // This instance need not autowired.
            }
        }
    

    最终调用了自动生成的类里面的inject方法,其实就是通过getIntent来对成员变量赋值

      @Override
      public void inject(Object target) {
        serializationService = ARouter.getInstance().navigation(SerializationService.class);
        MyLibActivity substitute = (MyLibActivity)target;
        substitute.name = substitute.getIntent().getStringExtra("name");
      }
    

    至此,整个流程分析完了。

    额外补充

    • Android Studio插件ARouterHelper可以方便的点击跳转到对应的类
    • 通过gradle插件router表信息
    apply plugin: 'com.alibaba.arouter'
    
     dependencies {
            classpath "com.alibaba:arouter-register:1.0.2"
       }
    

    相关文章

      网友评论

        本文标题:ARouter使用方式及源码学习

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