ARouter路由使用与源码分析(二)

汇总篇章:

ARouter路由源码分析汇总

简介

上一篇,我们将ARouter分成五步处理,上面我们了解了Arouter的init处理方法,对interceptor/provider等的加载逻辑,下面我们从剩下的路由和跳转取值完成对Arouter的了解

第三步:发起路由操作

// 1. 应用内简单的跳转(通过URL跳转在'进阶用法'中)
ARouter.getInstance().build("/test/activity").navigation();

// 2. 跳转并携带参数
ARouter.getInstance().build("/test/1")
            .withLong("key1", 666L)
            .withString("key3", "888")
            .withObject("key4", new Test("Jack", "Rose"))
            .navigation();
ARouter的Builder

ARouter.getInstance().build 将路径信息传递进ARouter内,进入方法中后,看到build方法的返回值Postcard类,由于Postcard类属性相对较多,这里只罗列部分

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;
    private int exitAnim;

    ...省略部分代码...
    
    public Object navigation(Context context, NavigationCallback callback) {
        return ARouter.getInstance().navigation(context, this, -1, callback);
    }
}
Postcard即是我们的盛放的参数信息

进入关键方法navigation方法在这里插入图片描述

navigation的第一个completion方法

public synchronized static void completion(Postcard postcard) {
        ...省略部分代码...
        /**
         * 通过Warehouse的routers中获取RouteMeta信息
         * Postcard就是RouteMeta实现
         */
        RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
  			/**
  			 * routeMeta为null,有可能是未加载进Warehouse的
  			 * 补充
  			 */
        if (null == routeMeta) {
          	/**
          	 * 先加载分组信息
          	 */
            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 {
                try {
                    ...省略部分代码...
										/**
										 * 加载分组信息和分组内的routes信息
										 */
                    IRouteGroup iGroupInstance = groupMeta.getConstructor().newInstance();
                    iGroupInstance.loadInto(Warehouse.routes);
                    Warehouse.groupsIndex.remove(postcard.getGroup());
										...省略部分代码...
                } catch (Exception e) {
                    ...省略部分代码...
                }

                completion(postcard);   // Reload
            }
        } else {
          	/**
						 * 从routeMeta获取信息,补充postcard,完善postcard信息
						 */
            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.
              	/**
                 * 设置参数进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()));
                    }

                    /**
                     * 补充Extras
                     */
                    postcard.getExtras().putStringArray(ARouter.AUTO_INJECT, paramsType.keySet().toArray(new String[]{}));
                }

                // Save raw uri
                postcard.withString(ARouter.RAW_URI, rawUri.toString());
            }
						/**
						 * 对PROVIDER类型和FRAGMENT类型,设置Green channel,跳过所有拦截器设置
						 */
            switch (routeMeta.getType()) {
                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;
                case FRAGMENT:
                    postcard.greenChannel();    // Fragment needn't interceptors
                default:
                    break;
            }
        }
    }

当onCompletion处理postcard匹配失败时,

如果NavigationCallback不为null则通过NavigationCallback的onLost通知失败;

如果NavigationCallback为null则尝试查找全局降级策略DegradeService,执行全局策略的onLost失败通知;

紧跟着LogisticsCenter.completion 对postcard处理后,如果postcard非greenChannel,则通过interceptor执行doInterceptions方法,做拦截器拦截业务处理

在这里插入图片描述
最后 进驻实现_navigation处理,也就是真正跳转方式的intent处理:

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:
            		/**
            		 * Activity的跳转intent处理
            		 */
                final Intent intent = new Intent(currentContext, postcard.getDestination());
                intent.putExtras(postcard.getExtras());

                int flags = postcard.getFlags();
                if (-1 != flags) {
                    intent.setFlags(flags);
                } else if (!(currentContext instanceof Activity)) {
                    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) {
                            ((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:
            		/**
            		 * 广播/contentProvider/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) {
                }
            case METHOD:
            case SERVICE:
            default:
                return null;
        }

        return null;
    }

第四步:跳转过程监听和参数解析

  • 跳转过程监听
    @Interceptor(priority = 8, name = "测试用拦截器")
    public class TestInterceptor implements IInterceptor {
        @Override
        public void process(Postcard postcard, InterceptorCallback callback) {
          //拦截逻辑
        }
    
        @Override
        public void init(Context context) {
        }
    }
    
    ARouter.getInstance().build(Uri.parse("arouter://beer.test/app/routeActivity"))
                    .navigation(this, new NavCallback() {
                        @Override
                        public void onArrival(Postcard postcard) {
                            Log.e("beerlib","==onArrival==");
                        }
    
                        @Override
                        public void onInterrupt(Postcard postcard) {
                            Log.e("beerlib","==onInterrupt==");
                        }
    
                        @Override
                        public void onFound(Postcard postcard) {
                            Log.e("beerlib","==onFound==");
                        }
    
                        @Override
                        public void onLost(Postcard postcard) {
                            Log.e("beerlib","==onLost==");
                        }
                    });
    

    在_navigation中,Activity类型:在跳转时通过NavigationCallback调用onArrival方法

    在navigation的completion方法异常时,通过NavigationCallback调用onLost方法;

    在navigation的completion方法正常执行时,通过NavigationCallback调用onFound方法;

  • 参数解析
    @Route(path = "/test/activity")
    public class Test1Activity extends Activity {
        @Autowired
        public String name;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
        	super.onCreate(savedInstanceState);
          ARouter.getInstance().inject(this);
    
          Log.d("param", name);
        }
    }
    
    @Route(path = "/yourservicegroupname/json")
    public class JsonServiceImpl implements SerializationService {
        @Override
        public void init(Context context) {
        }
    
        @Override
        public <T> T json2Object(String text, Class<T> clazz) {
            return JSON.parseObject(text, clazz);
        }
    
        @Override
        public String object2Json(Object instance) {
            return JSON.toJSONString(instance);
        }
    }
    
    ARouter的Inject

    ARouter的init方法结束,基本上属于初始化操作就结束了,接下来就是我们Activity等目标跳转的处理

    也就是我们使用的ARouter.getInstance().inject(this);

    也就从inject方法开始分析其对Activity的处理

    static void inject(Object thiz) {
            AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
            if (null != autowiredService) {
                autowiredService.autowire(thiz);
            }
        }
    
    
    对于"/arouter/service/autowired"这个的声明类是AutowiredServiceImpl
      
    @Route(path = "/arouter/service/autowired")
    public class AutowiredServiceImpl implements AutowiredService {
      	/**
      	 * 注入器的缓存集合
      	 */
        private LruCache<String, ISyringe> classCache;
      	/**
      	 * 黑名单集合
      	 */
        private List<String> blackList;
    
        @Override
        public void init(Context context) {
            classCache = new LruCache<>(66);
            blackList = new ArrayList<>();
        }
    
        @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.
            }
        }
    }
    
    我通过一个插件生成的器中一个注入器实例:
      examples:
    		public class RouteActivity$$ARouter$$Autowired implements ISyringe {
          private SerializationService serializationService;
    
          @Override
          public void inject(Object target) {
            /**
             * SerializationService这个方法内总共有三个方法
             * json2Object[该方法标记过时]/object2Json/parseObject
             * 如字面一个意思,就是对传递数据的json处理,也就是我们在页面中可以SerializationService获取传递的参数
             */
            serializationService = ARouter.getInstance().navigation(SerializationService.class);
            /**
             * 到这里豁然开朗,通过AutowiredServiceImpl的autowire执行此inject传入的当前页面信息
             * 通过获取getIntent,对我们Autowired的属性复制
             */
            RouteActivity substitute = (RouteActivity)target;
            substitute.name = substitute.getIntent().getStringExtra("name");
          }
        }
    
    

ARouter的整个jar代码层次的处理到这里就结束了,接下来通过新的一篇对ARouter插件的源码处理,辅助理解ARouter

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章