ARouter

作者: 要学的东西太多了 | 来源:发表于2019-01-03 09:48 被阅读0次

    1.ARouter主要用于不同组件的路由跳转,使用时,目标对象需要使用@Route注解,规则是@Route(path = "/xxx/xxx"),这里的一级路径必须唯一,一般跟moudle名相同,二级一般使用目标对象的类名,完整的路径不可重复,不然会报错。path必须"/"开头,且至少两级,在build方法里面有如下判断:

    if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {
                throw new HandlerException(Consts.TAG + "Parameter is invalid!");
            }
    

    build(path)方法会调用extractGroup(path)获取group,有如下判断:

    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 '/'!");
            }
    

    2.Arouter跳转,使用ARouter.getInstance().build("/xxx/xxx").navigation(),build里面的内容就是目标对象注解的路径,需要带参数的话可使用ARouter.getInstance().build("/xxx/xxx").with(new Bundle()).navigation(),也可以用其他类型的withXXX,支持基本类型、String、实现了Parcelable或Serializable接口的对象以及这些类型的集合和数组。此外,还支持withObject,要使用withObject,需要定义一个实现SerializationService接口的类,并加上@Route(path = "/service/json")注解,这个类需要实现解析的方法,实质上是对字符串的解析,例如:

    @Route(path = "/service/json")
    public class JsonServiceImpl implements SerializationService {
        private Gson mGson;
        @Override
        public <T> T json2Object(String input, Class<T> clazz) {
            check();
            return mGson.fromJson(input,clazz);
        }
    
        @Override
        public String object2Json(Object instance) {
            check();
            return mGson.toJson(instance);
        }
    
        @Override
        public <T> T parseObject(String input, Type clazz) {
            check();
            return mGson.fromJson(input,clazz);
        }
    
        @Override
        public void init(Context context) {
            check();
        }
    
        private void check(){
            if (mGson==null) {
                mGson = new Gson();
            }
        }
    }
    

    接收方可以用@Autowired注解标记字段,并调用ARouter.getInstance().inject(this)直接赋值,不用在intent里面去取值,@Autowired(name = "xxx")可以指定key。
    这里还有几点需要注意:

    (1).@Autowired注解标记的字段不能是private的。
    
    (2).withObject传递的对象不能实现Parcelable接口,实现了Parcelable接口的传递用withParcelable方法。
    
    (3).withObject有时候会出现接收方解析出的对象为空的情况,考虑以下解决思路:
    实体类提供显示的构造器;
    实体类的成员变量改成public类型;
    接收方的@Autowired注解的字段改成和传入的key名称一样。
    
    (4).withObject传递List或者map时,接收方@Autowired注解的字段不能是他们的实现类,如ArrayList。
    

    3.Arouter在使用时,使用Arouter的注解,如@Route、@Autowired等,build.gradle必须加如下语句,否则注解无法解析:

        android {
            ...
            defaultConfig {
                  ...
                  javaCompileOptions {
                      annotationProcessorOptions {
                            arguments = [ AROUTER_MODULE_NAME : project.getName() ]
                      }
                  }
            }
        }
        dependencies {
            ...
            //ARouter
            api 'com.alibaba:arouter-api:1.4.0'
            annotationProcessor 'com.alibaba:arouter-compiler:1.2.1'
        }
    

    4.Arouter的build也可以传入Uri,Uri必须指定path,build方法返回的是Postcard对象,在PendingIntent中需要传入Intent,可以用如下方式获取class:

    public static Class getRouterClass(String path){
            Postcard postcard = ARouter.getInstance().build(path);
            LogisticsCenter.completion(postcard);
            return postcard.getDestination();
        }
    

    startActivityForResult的实现方式是navigation(Context context,int requestCode),Intent设置flag的方式用withFlags方法,withTransition方法指定转场动画。

    5.Arouter可以自定义拦截器,例如:

    @Interceptor(name = "init",priority = 1)//priority 指定拦截顺序,越小排越前面
    public class InitInterceptorImpl implements IInterceptor {
        private static final String TAG = "InitInterceptorImpl";
        @Override
        public void process(Postcard postcard, InterceptorCallback callback) {
            String path = postcard.getPath();
            LogUtils.LogI(TAG,path);
            if(ARouterManager.PATH_AIDL_AIDL.equals(path)){//根据目标判断
                boolean v = KeyValueUtils.getInstance().get("hasInMeg");//判断条件
                if(v){
                    //不拦截,可以做其他操作,比如加参数
                    callback.onContinue(postcard);
                }else {
                    //表示拦截
                    callback.onInterrupt(new Throwable("请先打开Messenger页面"));
                }
            }else{
                callback.onContinue(postcard);
            }
        }
    
        @Override
        public void init(Context context) {
            LogUtils.LogI(TAG,"初始化拦截器");
        }
    }
    

    在跳转的时候调用navigation(Context context, NavigationCallback callback)方法。NavigationCallback的回调方法如下:

                        @Override
                        public void onFound(Postcard postcard) {
                            LogUtils.LogE(TAG,"onFound");//找到路由
                        }
    
                        @Override
                        public void onLost(Postcard postcard) {
                            LogUtils.LogE(TAG,"onLost");//未找到路由
                        }
    
                        @Override
                        public void onArrival(Postcard postcard) {
                            LogUtils.LogE(TAG,"onArrival");//跳转成功
                        }
    
                        @Override
                        public void onInterrupt(Postcard postcard) {
                            LogUtils.LogE(TAG,"onInterrupt");//被拦截
                        }
    

    注意NavigationCallback 的onInterrupt方法是在子线程,要进行UI操作需要切换线程。

    6.降级策略分两种,用于找不到路由的后续处理,第一种是上面的NavigationCallback 回调的onLost方法,这个是单独降级。另外一种是实现DegradeService 接口,是全局降级,例如:

    @Route(path = "/degrade/noInit")
    public class NoInitDealService implements DegradeService {
        private static final String TAG = "NoInitDealService";
        @Override
        public void onLost(Context context, Postcard postcard) {
            LogUtils.LogE(TAG,"降级策略");
        }
    
        @Override
        public void init(Context context) {
    
        }
    }
    

    单独降级的优先级高于全局,也就是说写了回调,就不会走全局的onLost。

    7.自定义服务可用于组件间调用接口,需要提供一个继承IProvider的接口,例如:

    public interface ISayHelloService extends IProvider {
        void say(String msg);
    }
    

    然后在需要实现的组件里面新增一个实现类,注意这个类不能为内部类,例如:

    @Route(path = "/main/say")
    public class SayImpl implements ISayHelloService {
        private static final String TAG = "SayImpl";
        private ICallBack mICallBack;
        @Override
        public void say(String msg) {
            if(mICallBack!=null){
                mICallBack.callBack(msg);
            }
        }
    
        public void setCallBack(ICallBack iCallBack) {
            mICallBack = iCallBack;
        }
    
        @Override
        public void init(Context context) {
    
        }
    
        public interface ICallBack{
            void callBack(String msg);
        }
    }
    

    其他组件调用接口可以用以下几种方式:
    注解:

    @Autowired
        ISayHelloService s1;
        @Autowired(name = "/main/say")
        ISayHelloService s2;
    
    ARouter.getInstance().inject(this);
            s1.say("1号");
            s2.say("2号");
    

    主动查找:

        private ISayHelloService s3;
        private ISayHelloService s4;
    
    s3 = ARouter.getInstance().navigation(ISayHelloService.class);
            s3.say("3号");
            s4 = (ISayHelloService) ARouter.getInstance().build("/main/say").navigation();
            s4.say("4号");
    

    这里要注意,如果这个接口有多个实现,一定要根据byname的方式来查找,即s2、s4的方式。

    8.原理分析:
    Arouter的主要原理是通过注解和注解解释器生成java文件,在调用ARouter.init(this)方法时,调用_ARouter的init方法:

    public static void init(Application application) {
            if (!hasInit) {
                //...
                hasInit = _ARouter.init(application);
                if (hasInit) {
                    _ARouter.afterInit();
                }
                //...
            }
        }
    

    在里面调用LogisticsCenter的init方法,这里初始化了一个主线程的handler:

    protected static synchronized boolean init(Application application) {
            //...
            LogisticsCenter.init(mContext, executor);
            //...
            mHandler = new Handler(Looper.getMainLooper());
            return true;
        }
    

    LogisticsCenter的init方法里面,找到前面通过注解解释器生成的java文件类名集合,然后循环调用对象的loadInto,loadInto把path和注解的目标类放到路由表里面:

    public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
            mContext = context;
            executor = tpe;
            //...
            Set<String> routerMap;
           //...
            routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);
            //...
           for (String className : routerMap) {
                 if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
                      //这里先保存各个分组对应的IRouteGroup类,IRouteGroup里面保存了各个路径对应的RouteMeta对象,RouteMeta对象的RouteType是ACTIVITY,且保存了目标class对象
                      ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
                } else if ( className.startsWith ( ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS ) ) {
                    //这里根据priority保存了IInterceptor对象
               ((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
               } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
                    //这里根据服务类型,保存了对应的RouteMeta对象,RouteMeta对象里面有目标服务的class对象
                      ((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
                    }
                 }
             }
          //...
    

    getFileNameByPackageName方法扫描目标包下面的所有类的类名:

    public static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException {
            final Set<String> classNames = new HashSet<>();
            List<String> paths = getSourcePaths(context);
            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)) {
                                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();
            return classNames;
        }
    

    这里路由表的初始化就完成了,在调用页面跳转的时候,ARouter.getInstance().build(uri)返回的是一个PostCard对象,navigation方法会调用Arouter对象的navigation方法,接着调用_ARouter的navigation方法,重点看下_ARouter的navigation方法:

    protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            //...
            //这个方法里面会从路由表里面,根据path找到RouteMeta对象,找到了就将目标对象的class赋给PostCard,如果没找到,会先找IRouteGroup对象,并主动调用IRouteGroup的loadInto方法,把对应的class放进路由表,然后递归回来重新找。
           LogisticsCenter.completion(postcard);
            //..try-catch块里面,如果没找到目标对象,会回调 callback.onLost(postcard)
            //没抛异常,说明找到了,会回调onFound
            if (null != callback) {
                callback.onFound(postcard);
            }
            //这里判断需不需要走拦截器
            if (!postcard.isGreenChannel()) {   
                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);
                        }
                    }
                });
            } else {
                return _navigation(context, postcard, requestCode, callback);
            }
    
            return null;
        }
    

    上面的方法没拦截的情况都会走_navigation方法,这里面做了具体的跳转:

    private Object _navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
            final Context currentContext = null == context ? mContext : context;
            switch (postcard.getType()) {
                case ACTIVITY:
                    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)) {    // Non activity, need less one flag.
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    }
                    String action = postcard.getAction();
                    if (!TextUtils.isEmpty(action)) {
                        intent.setAction(action);
                    }
                    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;
        }
    

    跳转完成了,那些参数是怎么自动赋值的呢,主要逻辑在ARouter.getInstance().inject(this)方法里面,在_ARouter的inject方法里面,会调用AutowiredService的autowire方法:

    static void inject(Object thiz) {
            AutowiredService autowiredService = ((AutowiredService) ARouter.getInstance().build("/arouter/service/autowired").navigation());
            if (null != autowiredService) {
                autowiredService.autowire(thiz);
            }
        }
    

    AutowiredService的实现类AutowiredServiceImpl里面,autowire做了什么操作呢:

    @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.
                        //这里是重点,找到目标类,并调用inject方法,在注解自动生成的$$ARouter$$Autowired类里面,inject方法会将传入的target对象强转为本身的类型,然后对注解的对象进行赋值,所赋的值是通过getIntent().getXXXExtra()的方式获取的
                        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.
            }
        }
    

    相关文章

      网友评论

          本文标题:ARouter

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