精华内容
下载资源
问答
  • ARouter

    2019-12-24 10:03:44
    更快捷的同步开发与更简单的单独调试,而ARouter的出现就是让组件间、模块间是实现完全的独立。 ARouter是:阿里巴巴自研路由框架,主要解决组件间、模块间的 界面跳转 问题。 今天用最简单的方式讲解Arouter的...

    1.前言

    • 组件化或者模块化开发模式,已逐渐成为热浪的形式,使用这些模式可以让我们程序更容易的扩展、更方便的维护
      更快捷的同步开发与更简单的单独调试,而ARouter的出现就是让组件间、模块间是实现完全的独立。
    • ARouter是:阿里巴巴自研路由框架,主要解决组件间、模块间的 界面跳转 问题。
    • 今天用最简单的方式讲解Arouter的使用与原理。
    • 文章中实例 linhaojian的Github

    2.目录

    arouter目录.png


    3.简介

    arouter简介.png


    4.原理

    4.1 关系分析

    • 从A界面跳转到B界面这个过程,我们看看arouter与界面间关系,如下图:

       

      arouter与界面关系.png

    • 1.注册

    B界面将类的信息,通过key-value的形式,注册到arouter中。

    • 2.查询

    A界面将类信息与额外信息(传输参数、跳转动画等),通过key传递至arouter中,并查询对应需要跳转类的信息。

    • 3.结合

    将A界面类信息、参数与B界面的类信息进行封装结合。

    • 4.跳转

    将结合后的信息,使用startActivity实现跳转。

    4.2 流程分析

    • A界面跳转到B界面,arouter做了以下工作:

       

      arouter流程.png

    从上图流程中,我们可以发现Arouter中原理:
    1.通过apt技术利用注解编译时生成类,封装目标界面类的类信息。
    2.在初始化时,把编译生成的类通过key-value的方式存储在arouter中。
    3.发送操作者通过key获取到目标界面类的信息。
    4.把发送操作者的信息与目标界面类信息进行结合或者关联在一起。
    5.实现跳转功能。

    • 其实简单概括:将需要相互跳转的界面信息传递至arouter中存储关联 & 实现跳转。

    5.使用

    5.1 跳转界面不带参

    • 发送跳转操作

     

    // 1. 普通跳转
    ARouter.getInstance().build("/test/activity").navigation();
    
    • 目标界面

     

    // 在支持路由的页面上添加注解(必选)
    // 这里的路径需要注意的是至少需要有两级,/xx/xx
    @Route(path = "/test/activity")
    public class YourActivity extend Activity {
        ...
    }
    

    5.2 跳转界面带参

    • 发送跳转操作

     

    ARouter.getInstance().build("/test/1")
                .withLong("key1", 666L)
                .withString("key3", "888")
                .withSerializable("key4", new Test("Jack", "Rose"))
                .navigation();
    
    • 目标界面

     

    @Route(path = "/test/1")
    public class YourActivity extend Activity {
        //获取数据三种方式
        //1.通过Autowired注解表明key   &  需要在onCreate中调用ARouter.getInstance().inject(this);配合使用
        @Autowired(name = "key1")
        public long data;
        //2.通过Autowired注解 & 将key1作为属性的名称   &  需要在onCreate中调用ARouter.getInstance().inject(this);配合使用
        @Autowired()
        public long key1;
        //3.通过Bundle获取
        getIntent().getExtras().getLong("key1")
    }
    

    5.3 跳转界面带参(传递Object)

    • 定义解析Obeject的SerializationService

     

    /**
     * 处理传递参数中自定义的Object---》withObject
     */
    @Route(path = "/custom/json")
    public class JsonSerializationService implements SerializationService {
        Gson gson;
        @Override
        public <T> T json2Object(String input, Class<T> clazz) {
            return gson.fromJson(input,clazz);
        }
        @Override
        public String object2Json(Object instance) {
            return gson.toJson(instance);
        }
        @Override
        public <T> T parseObject(String input, Type clazz) {
            return gson.fromJson(input,clazz);
        }
        @Override
        public void init(Context context) {
            gson = new Gson();
        }
    }
    
    • 发送跳转操作

     

    ARouter.getInstance().build("/test/1")
                .withObejct("key4", new Test("Jack", "Rose"))
                .navigation();
    
    • 目标界面

     

    @Route(path = "/test/1")
    public class YourActivity extend Activity {
        ...
        SerializationService serializationService = ARouter.getInstance().navigation(SerializationService.class);
        serializationService.init(this);
        User obj = serializationService.parseObject(getIntent().getStringExtra("key4"), User.class);
    }
    

    5.4 Uri跳转

    • 界面配置

     

    <activity android:name=".activity.SchameFilterActivity">
        <!-- Schame -->
        <intent-filter>
            <data
            android:host="m.aliyun.com"
            android:scheme="arouter"/>
            <action android:name="android.intent.action.VIEW"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <category android:name="android.intent.category.BROWSABLE"/>
        </intent-filter>
    </activity>
    
    • 发送跳转操作

     

     Uri testUriMix = Uri.parse("arouter://m.aliyun.com/test/activity2");
                    ARouter.getInstance().build(testUriMix)
                            .withString("key1", "value1")
                            .navigation();
    
    • 目标界面

     

    @Route(path = "/test/activity2")
    public class Test2Activity extends AppCompatActivity {
    }
    

    5.5 跳转结果监听

     

     ARouter.getInstance()
                  .build("/test/activity2")
                  .navigation(this, new NavCallback() {
                       @Override
                        public void onArrival(Postcard postcard) {
                         }
                         @Override
                         public void onInterrupt(Postcard postcard) {
                               Log.d("ARouter", "被拦截了");
                          }
                     });
    

    5.6 声明拦截器(拦截跳转过程,面向切面编程)

     

    // 比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查
    // 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行
    @Interceptor(priority = 8, name = "测试用拦截器")
    public class TestInterceptor implements IInterceptor {
        @Override
        public void process(Postcard postcard, InterceptorCallback callback) {
        ...
        callback.onContinue(postcard);  // 处理完成,交还控制权
        // callback.onInterrupt(new RuntimeException("我觉得有点异常"));      // 觉得有问题,中断路由流程
        // 以上两种至少需要调用其中一种,否则不会继续路由
        }
        @Override
        public void init(Context context) {
        // 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次
        }
    }
    

    5.7 为目标页面声明更多信息

     

    // 我们经常需要在目标页面中配置一些属性,比方说"是否需要登陆"之类的
    // 可以通过 Route 注解中的 extras 属性进行扩展,这个属性是一个 int值,换句话说,单个int有4字节,也就是32位,可以配置32个开关
    // 剩下的可以自行发挥,通过字节操作可以标识32个开关,通过开关标记目标页面的一些属性,在拦截器中可以拿到这个标记进行业务逻辑判断
    @Route(path = "/test/activity", extras = Consts.XXXX)
    

    5.8 依赖注入解耦

    • 注册需要依赖注入的对象

     

    @Route(path = "/provider/testP")
    public class TestProvider implements IProvider {
        @Override
        public void init(Context context) {
        }
        public String test(){
           return ("Hello Provider!");
        }
    }
    
    • 获取对象 & 使用

     

    ARouter.getInstance().navigation(TestProvider.class).test();
    

    6.总结

    • 到此,ARouter就讲解完毕。



    作者:Linhaojian
    链接:https://www.jianshu.com/p/8098961bd30c
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    展开全文
  • Search for ARouter Helper in the Android Studio plugin market, or directly download the arouter-idea-plugin zip installation package listed in the Latest version above the documentation, after ...
  • ARouterDemo

    2017-04-25 17:31:18
    该demo讲解了ARouter的简单使用
  • ARouterDemo源码

    2020-10-20 15:11:40
    组件化开发推荐目前比较流行的ARouter框架,ARouter是由阿里开发团队开源的组件化框架,目前应用比较多,ARouter经过多年广大开发者测验并改进已经比较完善,选择阿里团队一直有维护更新的ARouter更稳妥一些。
  • ARouter浅析

    2020-08-18 00:54:25
    ARouter ARouter是:阿里巴巴自研路由框架,主要解决组件间、模块间的 界面跳转 问题。 基本使用 首先按步骤引入这个库ARouter ARouter.getInstance() .build("/module_second/second") .withString("data", ...

    ARouter

    ARouter是:阿里巴巴自研路由框架,主要解决组件间、模块间的 界面跳转 问题。

    原理

    • 使用apt在编译阶段生成代码
    • 分组+按需加载 路由列表
    • 内部使用Intent进行跳转

    原理解析

    //创建的第一个使用Router注解的Activity
    @Route(path = "/module_main/two")
    public class TwoActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_two);
            Toast.makeText(this, getLocalClassName(), Toast.LENGTH_SHORT).show();
        }
    }
    
    
    //第二个
    @Route(path = "/module_comm/comm")
    public class CommActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_comm);
            Toast.makeText(this, getLocalClassName(), Toast.LENGTH_SHORT).show();
        }
    }
    
    
    //第三个
    @Route(path = "/module_second/second")
    public class SecondActivity extends AppCompatActivity {
        @Autowired
        String data;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ARouter.getInstance().inject(this);
            TextView textView = new TextView(this);
            textView.setText(data);
            setContentView(textView);
        }
    }
    

    这三个类分别在不同的module里面

    接下来我们编译一下这个项目,看都生成了哪些代码

    //第一个module
    public class ARouter$$Group$$module_main implements IRouteGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> atlas) {
        atlas.put("/module_main/two", RouteMeta.build(RouteType.ACTIVITY, TwoActivity.class, "/module_main/two", "module_main", null, -1, -2147483648));
      }
    }
    
    public class ARouter$$Providers$$app implements IProviderGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> providers) {
      }
    }
    
    public class ARouter$$Root$$app implements IRouteRoot {
      @Override
      public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
        routes.put("module_main", ARouter$$Group$$module_main.class);
      }
    }
    
    //第二个module
    public class ARouter$$Group$$module_comm implements IRouteGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> atlas) {
        atlas.put("/module_comm/comm", RouteMeta.build(RouteType.ACTIVITY, CommActivity.class, "/module_comm/comm", "module_comm", null, -1, -2147483648));
      }
    }
    
    public class ARouter$$Providers$$module_comm implements IProviderGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> providers) {
      }
    }
    
    public class ARouter$$Root$$module_comm implements IRouteRoot {
      @Override
      public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
        routes.put("module_comm", ARouter$$Group$$module_comm.class);
      }
    }
    
    //第三个module
    public class ARouter$$Group$$module_second implements IRouteGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> atlas) {
        atlas.put("/module_second/second", RouteMeta.build(RouteType.ACTIVITY, SecondActivity.class, "/module_second/second", "module_second", new java.util.HashMap<String, Integer>(){{put("data", 8); }}, -1, -2147483648));
      }
    }
    
    public class ARouter$$Providers$$module_second implements IProviderGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> providers) {
      }
    }
    
    public class ARouter$$Root$$module_second implements IRouteRoot {
      @Override
      public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
        routes.put("module_second", ARouter$$Group$$module_second.class);
      }
    }
    
    //这里是给用Autowired注解的变量赋值
    public class SecondActivity$$ARouter$$Autowired implements ISyringe {
      private SerializationService serializationService;
    
      @Override
      public void inject(Object target) {
        serializationService = ARouter.getInstance().navigation(SerializationService.class);
        SecondActivity substitute = (SecondActivity)target;
        substitute.data = substitute.getIntent().getStringExtra("data");
      }
    }
    

    我们可以看到基本每个module至少会生成三个类ARouter$$Providers$$***是空实现暂时不管它,我们看下ARouter$$Group$$Comm

    public class ARouter$$Group$$module_comm implements IRouteGroup {
      @Override
      public void loadInto(Map<String, RouteMeta> atlas) {
        atlas.put("/module_comm/comm", RouteMeta.build(RouteType.ACTIVITY, CommActivity.class, "/module_comm/comm", "module_comm", null, -1, -2147483648));
      }
    }
    

    这里可以看到在loadInto中是将用Router注解的类以path的值为key,类的class为value存在了Map中,ps所有@Router注解path值斜杠后第一个值相同的类都会在同一个类中被管理起来

    public class ARouter$$Root$$module_comm implements IRouteRoot {
      @Override
      public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
        routes.put("module_comm", ARouter$$Group$$module_comm.class);
      }
    }
    

    这里将Router注解的path的斜杠后的第一个值为key,将ARouter$$Group$$module_comm.class为value存在了map中,这样的话我们是不是可以认为ARouter会将Router注解path斜杠后的第一个值相同的类分为了一个组,使用apt生成这个组的管理类,也就是我们现在的ARouter$$Group$$module_comm

    在这里我们了解到ARouter是怎么进行分组的,接下来我们看下ARouter是怎么获取到我们的这些类的

    ARouter.openLog();     // 打印日志
    ARouter.openDebug();   // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
    ARouter.init(getApplication()); // 尽可能早,推荐在Application中初始化
    
        public static void init(Application application) {
            if (!hasInit) {
                logger = _ARouter.logger;
                _ARouter.logger.info(Consts.TAG, "ARouter init start.");
                hasInit = _ARouter.init(application);
    
                if (hasInit) {
                    _ARouter.afterInit();
                }
    
                _ARouter.logger.info(Consts.TAG, "ARouter init over.");
            }
        }
    
    	  protected static synchronized boolean init(Application application) {
    	        mContext = application;
    	        LogisticsCenter.init(mContext, executor);
    	        logger.info(Consts.TAG, "ARouter init success!");
    	        hasInit = true;
    	        mHandler = new Handler(Looper.getMainLooper());
    	
    	        return true;
    	    }
    	
    	  //代码有删减
    	  public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
    	        tr {
    	                if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {
    	                    logger.info(TAG, "Run with debug mode or new install, rebuild router map.");
    	                    // These class was generated by arouter-compiler.
    	                    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 {
    	                    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();
    	
    	                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() + "]");
    	        }
    	    }
    

    routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);我们直接看到这一行

        public static Set<String> getFileNameByPackageName(Context context, final String packageName) throws PackageManager.NameNotFoundException, IOException, InterruptedException {
            final Set<String> classNames = new HashSet<>();
    		//拿到了apk安装之后的路径
            List<String> paths = getSourcePaths(context);
            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();
                            //便利dex下的类
                            while (dexEntries.hasMoreElements()) {
                                String className = dexEntries.nextElement();
                                //找到包名是com.alibaba.android.arouter.routes开头的类
                                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) {
                                }
                            }
                        }
                    }
                });
            }
            return classNames;
        }
    

    这里传进来的packgeName = com.alibaba.android.arouter.routes 这个函数执行完就能拿到之前我们看到的几个类.因为我们编译之后生成的类的包名恰好是com.alibaba.android.arouter.routes

    接下来我们继续看到LogisticsCenter类的init函数

     public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
          ...
        for (String className : routerMap) {
            if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
            ((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
             } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
              ((IInterceptorGroup(Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
            } else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
          }
          ...
        }
    

    这里就是拿到apt生成的类并且调用他们的loadInto()当然这里还没有调用具体某个组loadInto所以实际path与类的映射还没加载到内存,这样做达到了节省内存的效果,这里把每个组的管理类的class添加到了Warehouse.groupsIndex中,后续我们要取出具体组的映射关系也是相当简单的事情

    到这里ARouter的init()事情已经做完了我们在看一下在哪里才会取出具体组的映射呢

           ARouter.getInstance()
                    .build("/module_second/second")
                    .navigation();
    

    我们通常是这样进行页面的跳转那我们接下来就看下navigation()都做了些什么事

        protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {
          		...
                LogisticsCenter.completion(postcard);
           		...
                return _navigation(context, postcard, requestCode, callback);
            	....
        }
    
    
        public synchronized static void completion(Postcard postcard) {
            if (null == postcard) {
                throw new NoRouteFoundException(TAG + "No postcard!");
            }
    
            RouteMeta routeMeta = Warehouse.routes.get(postcard.getPath());
        	//当前的map中没有对应这个path的class
            if (null == routeMeta) { 
            	//取出这个path所在组的管理类
                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();
                        //将这个组的所有数据添加到map
                        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() + "]");
                    }
    				//重新调这个函数,下次走else分子
                    completion(postcard);   // Reload
                }
            } else {
            	//填充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.
                    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;
                }
            }
        }
    

    从上面代码我们看到了ARouter的按需加载,我们在继续看下ARouter是怎么进行跳转的

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

    从这里我们可以看到其实ARouter内部跳转还是使用的Intent,那为什么我们使用组件化开发引用不到别的module中的类但是在ARouter中却可以,那是因为在进行apk的过程中会把所有类在一起进行打包,所以在组件化项目中我们使用ARouter既方便又能达到解耦合的效果岂不美哉

    展开全文
  • ARouter跳转

    2019-09-28 16:50:09
    ARouter跳转介绍代码使用新建Application ,初始化ARouter在要跳转的Activity添加头注释被跳转的页面 介绍 ARouter是阿里开源的一款android路由框架。 通过路由进行界面跳转,区别于 Intent的显隐式跳转。在模块化的...

    介绍

    ARouter是阿里开源的一款android路由框架。
    通过路由进行界面跳转,区别于 Intent的显隐式跳转。在模块化的项目中,友好的解决了因模块互相依赖冲突,而界面互相跳转不了的问题,使用ARouter进行跳转,两个 library互相不依赖,也可以相互跳转。

    代码使用

    在要使用ARouter的应用添加 build配置 和 依赖:

     defaultConfig {
            ...
    
            javaCompileOptions {
                annotationProcessorOptions {
                    arguments = [AROUTER_MODULE_NAME: project.getName()]
                }
            }
        }
    

    依赖:
    implementation (‘com.alibaba:arouter-api:1.4.1’)
    annotationProcessor ‘com.alibaba:arouter-compiler:1.2.2’

    新建Application ,初始化ARouter

    public class App extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            // 打印日志
            ARouter.openLog();
            // 开启调试模式(如果在InstantRun(就是AndroidStudio2.0以后新增的一个可以减少很多编译时间的运行机制)模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
            ARouter.openDebug();
            // 初始化尽可能早,推荐在Application中初始化
            ARouter.init(this);
        }
    }
    

    在要跳转的Activity添加头注释

    path:module名+activity名

    @Route(path="/app/MainActivity")
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    }
    

    需要跳转的地方 :
    可以传值

     public void click(View view) {
    
            //点击事件内  跳转
            ARouter.getInstance()
                    .build("/modules1/Modules1MainActivity")
                    .withString("name","a三")  // 传递的值
                    .navigation();
        }
    

    被跳转的页面

    同样需要头注释
    在这里插入图片描述

    
        TextView textView;
    
        @Autowired(name = "name")
        String name;
        @SuppressLint("WrongViewCast")
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_modules1_main);
    
    
            //接收
            ARouter.getInstance().inject(this);
            //name 接受完以后直接设置到控件上
    
            textView=findViewById(R.id.edit_text);
            textView.setText(name);
        }
    
    展开全文
  • ARouterDemo.zip

    2020-12-18 00:02:49
    是继承的阿里的ARouter,以及实现了模块化通过ARouter实现了之间的跳转
  • ARouter使用

    2019-12-24 20:59:03
    ARouter 是阿里开源的,可以看成是 Android 平台中对页面、服务提供路由功能的中间件。 ARouter 直接翻译过来就是路由,可以用来映射页面关系,实现跳转相关的功能。在 Android 中,常被用来进行组件化通讯。 为...

    简介

    ARouter 是阿里开源的,可以看成是 Android 平台中对页面、服务提供路由功能的中间件。

    ARouter 直接翻译过来就是路由,可以用来映射页面关系,实现跳转相关的功能。在 Android 中,常被用来进行组件化通讯。


    为什么要使用 ARouter

    我们知道 Android 中默认为我们提供了跳转的功能,比如 startActivity,startService 等。那为什么还需要路由框架呢?在我看来,主要有以下几点吧:

    • 在一些复杂的业务场景下(比如电商),灵活性比较强,很多功能都是运营人员动态配置的,比如下发一个活动页面,我们事先并不知道具体的目标页面,但如果事先做了约定,提前做好页面映射,便可以自由配置。

    • 随着业务量的增长,客户端必然随之膨胀,开发人员的工作量越来越大,比如64K问题,比如协作开发问题。App一般都会走向组件化、插件化的道路,而组件化、插件化的前提就是解耦,那么我们首先要做的就是解耦页面之间的依赖关系。


    ARouter 基本使用

    ARouter github 地址: ARouter

    ARouter 的接入也非常简单,一般来说,需要以下几个步骤。

    第一步:配置 gradle 文件

    android {
        defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
            arguments = [ moduleName : project.getName() ]
            }
        }
        }
    }
    
    dependencies {
        // Replace with the latest version
        compile 'com.alibaba:arouter-api:?'
        annotationProcessor 'com.alibaba:arouter-compiler:?'
        ...
    }

    第二步:初始化 SDK

    if (isDebug()) {           // These two lines must be written before init, otherwise these configurations will be invalid in the init process
        ARouter.openLog();     // Print log
        ARouter.openDebug();   // Turn on debugging mode (If you are running in InstantRun mode, you must turn on debug mode! Online version needs to be closed, otherwise there is a security risk)
    }
    ARouter.init(mApplication); // As early as possible, it is recommended to initialize in the Application

    第三步:添加 @Route 注解

    // Add annotations on pages that support routing (required)
    // The path here needs to pay attention to need at least two levels : /xx/xx
    @Route(path = ARouterConstants.COM_ACTIVITY1)
    public class ActivityOne extends AppCompatActivity {
    
        -----
    }
     public static final String COM_ACTIVITY1 = COM + "Activity1";

    第四步:调用跳转的代码

    ARouter.getInstance().build(ARouterConstants.COM_ACTIVITY1).navigation();

    Activity 之间的跳转

    假设我们现在要从 A 页面跳转到 B 页面,那我们要怎么办呢?

    第一步:在目标页面使用 @Route 注解,并指定 path

    @Route(path = ARouterConstants.COM_ACTIVITY1)
    public class ActivityOne extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_one);
        }
    }
    

    第二步:调用 navigation 方法实现跳转

    ARouter.getInstance().build(ARouterConstants.COM_ACTIVITY1).navigation();
    

    这样,从 A 跳转到 B 的功能便实现了。

    传递参数

    Arouter 的跳转页非常简单,我们可以调用 PostCard 的 withX 等方法传递相应的参数

    比如,我们想传递 String,可以调用 withString,想传递 int,可以调用 withInt ,想传递 Parceable 对象,可以调用 withParcelable。

    ARouter.getInstance().build(ARouterConstants.COM_PARSE_ACTIVITY).withString(NAME,"jun")
            .withInt(AGE,1).withParcelable(PERSON,person).withObject(TEST_OBJ,testObj)
    

    同时 ARouter 还支持传递 Object 对象,只需调用 withObject 方法,同时需要在我们的 moudle 下面增加相关的类。实际上,它的原理是通过将 object 转化成 String,然后存进 intent 中,在解析参数的时候,再通过相应的 key 去除 String,然后转化成 object。

    如果你的项目使用的是 Gson,那可以使用下面的类

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

    如果你的项目使用的是阿里巴巴的 fastjson,那可以在你的项目增加该类。

    @Route(path = "/service/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);
        }
    
        @Override
        public <T> T parseObject(String input, Type clazz) {
            return JSON.parseObject(input, clazz);
        }
    }
    
    

    解析参数

    在 ActivityB 中获取参数有两种方式

    • 一种是普通 Activity 那样 getIntent().getXXX,这里就不展开了
    • 另外一种是使用 @Autowired 注解的方式,记得需要在接收参数地方ARouter.getInstance.inject(thhis)
    @Route(path = ARouterConstants.COM_PARSE_ACTIVITY)
    public class ParseActivity extends AppCompatActivity {
    
        private static final String TAG = "ParseActivity";
    
    
        @Autowired
        String name;
    
        @Autowired
        int age;
    
        @Autowired
        Person person;
    
        @Autowired
        TestObj mTestObj;
    
        @Autowired // 注意字段的名称必须与 withObject 的 key 一致
        TestObj testObj;
        private android.widget.TextView tv;
        
        
            @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_parse);
            // 调用 inject 方法,如果传递过来的参数含有,这样使用 @Autowired 的会自动解析 
            ARouter.getInstance().inject(this);
    }
    

    实现跳转并获取返回结果

    在 activity 的跳转中,我们知道,我们可以用 startActivityForResult 来获取返回结果,那在 ARouter 中要怎么实现呢。

    ARouter 中并没有提供这样的接口,但是我们可以采用曲线救国的原理,通过 Postcard 实现

    Postcard postcard = ARouter.getInstance().build(ARouterConstants.COM_ACTIVITY_RESULT);
    LogisticsCenter.completion(postcard);
    Class<?> destination = postcard.getDestination();
    

    这里得到的 destination 类就是我们要跳转的类,这样 fragment 的 startActivityForResult 就好办了

    Intent intent = new Intent(getContext(),destination);
    startActivityForResult(intent,requestCode);
    

    暴露服务

    这里说到的服务不是 Android 四大组件中的 Service,这里的服务是接口开发的概念。即把部分功能或者业务封装起来。

    比如,我们想调用某个接口,一般来说,可以这样做。

    • 首先我们定义一个接口,并实现该接口,并采用 @Route 注解指定相应的 path:
    public interface HelloService extends IProvider {
        String sayHello(String name);
    }
    

     

    // 实现接口
    @Route(path = ARouterConstants.SERVICE_HELLO, name = "test service")
    public class HelloServiceImpl implements HelloService {
    
        private Context mContext;
    
        @Override
        public String sayHello(String name) {
            Toast.makeText(mContext,this.getClass().getSimpleName()+": sayHello"+" "+name,Toast.LENGTH_SHORT).show();
            return "hello, " + name;
        }
    
        @Override
        public void init(Context context) {
            mContext = context;
        }
    }
    
    
    • 接着调用 Poatcard 的 navigation 方法获取到我们的实例:

     

    HelloService helloService = (HelloService) ARouter.getInstance().build(ARouterConstants.SERVICE_HELLO).navigation();
    String result = helloService.sayHello("xujun");
    

    URL 跳转

    我们先来看一下我们 URL 跳转的设计

    从图中可以看到,我们是用一个中间跳转页面来管理所有 Activity 的跳转的,当接受到跳转指令的时候,中转 Activity 会进行相应的处理,从而跳转到响应的页面。

    这样设计的好处是:

    • 我们的目标 Activity(页面 A,页面 B 等)不需要对外暴露

    中转 Activity:

     

    public class UrlSchemeActivity extends AppCompatActivity {
    
        private static final String TAG = "UrlSchemeActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_url);
            //        直接通过ARouter处理外部Uri
            final Uri uri = getIntent().getData();
            Log.i(TAG, "onCreate: uri=" + uri);
            ARouter.getInstance().build(uri).navigation(this, new NavCallback() {
                @Override
                public void onArrival(Postcard postcard) {
                    finish();
                }
    
                @Override
                public void onLost(Postcard postcard) {
                    super.onLost(postcard);
                    Log.i(TAG, "onLost: uri=" + uri);
                    //                Toast.makeText(UrlSchemeActivity.this,String.format("找不到可以处理该
                    // URI %s 的 Activity",uri),Toast.LENGTH_SHORT).show();
                    // 找不到的时候 finish 掉当前 activity
                    finish();
                }
            });
            
        }
    }
    

    当我们接收到跳转 uri 的时候,我们将它交给路由 ARouter,去进行分发。

    接下来我们来看一下我们在 AndroidManifest 的配置

     

    <activity android:name=".testAcivity.UrlSchemeActivity">
        <intent-filter>
            <data
                android:host="m.aliyun.com"
                android:scheme="arouter"/>
    
            <action android:name="android.intent.action.VIEW"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <category android:name="android.intent.category.BROWSABLE"/>
        </intent-filter>
    </activity>
    
    
    

    这里面的 host 、scheme 字段很重要。点击 url 会根据这两个字段会调起本地的 Activity 。

    接下来,看一下我们的 HTML

     

    <!DOCTYPE html>
    <html>
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
        <title></title>
    </head>
    
    <body>
    
    <h2>跳转测试</h2>
    
    <h2>自定义Scheme[通常来说都是这样的]</h2>
    <p>
        <a href="arouter://m.aliyun.com/test/activity1">arouter://m.aliyun.com/test/activity1
        </a>
    </p>
    <p>
        <a href="arouter://m.aliyun.com/test/activity1?url=https%3a%2f%2fm.abc.com%3fa%3db%26c%3dd">
            测试URL Encode情况
        </a>
    </p>
    <p>
        <a href="arouter://m.aliyun.com/test/activity1?name=alex&age=18&boy=true&high=180&obj=%7b%22name%22%3a%22jack%22%2c%22id%22%3a666%7d">
            arouter://m.aliyun.com/test/activity1?name=alex&age=18&boy=true&high=180&
            obj={"name":"jack","id":"666"}
        </a>
    </p>
    
    </body>
    </html>
    
    

    注意 a 标签里面的 arouter://m.aliyun.com 分别代表着 scheme 、host ;/com/URLActivity1 就是目标 Activity 的注解。

    如果需要接收 URL 中的参数,需要在 Activity 调用自动注入初始化方法;

     

    ARouter.getInstance().inject(this);
    

    需要注意的是,如果不使用自动注入,那么可以不写 ARouter.getInstance().inject(this),但是需要取值的字段仍然需要标上 @Autowired 注解,因为 只有标上注解之后,ARouter 才能知道以哪一种数据类型提取 URL 中的参数并放入 Intent 中,这样您才能在 intent 中获取到对应的参数


    其他用法

    监听 ARouter 的执行过程,两种方式:

    监听单一路由执行:

     

    /**
         * 测试单一路由,降级监听,例如单一路由失败的话进行后续处理
         */
        private void ARouterCallBack() {
            ARouter.getInstance()
                    .build("/com/hq")
                    .navigation(this, new NavCallback() {
    
                        @Override
                        public void onFound(Postcard postcard) {
                            Log.e(TAG, "onArrival: 找到了 ");
                        }
    
                        @Override
                        public void onLost(Postcard postcard) {
                            Log.e(TAG, "onArrival: 找不到了 ");
                            Toast.makeText(MainActivity.this, "未找到目标页面 path=" + postcard.getPath() + " group=" + postcard.getGroup() +
                                    " 做降级处理,5s后跳转降级页", Toast.LENGTH_LONG).show();
                            jumpDegradePage(MainActivity.this, postcard);
                        }
    
                        @Override
                        public void onArrival(Postcard postcard) {
                            Log.e(TAG, "onArrival: 跳转完了 ");
                        }
    
                        @Override
                        public void onInterrupt(Postcard postcard) {
                            Log.e(TAG, "onArrival: 被拦截了 ");
                        }
                    });
        }

    在当前的 moudle 中,如果有找到 @Route(path=ARouterConstants.COM_ACTIVITY1) 注解的目标 activity,会先后回调 onFound,onArrival;如果找不到的话,会回调 onLost;如果被拦截了,会回调 onInterrupt 方法。

    执行全局路由监听:

    首先注册需要跳转的页面:

        /**
         * 测试全局降级监听,全局路由监听,当找不到目标页面时,会调用DefaultDegrade
         * 走onLost方法,处理找不到页面的后续操作
         */
        private void ARouterDownDelegate() {
            ARouter.getInstance().build("/com/hq").navigation();
        }

    然后实现DegradeService,在这里进行全局路由监听:

    /**
     * 全局降级监听,当找不到目标页面时,会调用这里
     */
    @Route(path = "/hehe/1a")
    public class DefaultDegrade implements DegradeService {
    
        @Override
        public void onLost(Context context, Postcard postcard) {
            Log.e("buder", "onLost");
            if (context instanceof Activity) {
                Toast.makeText(context, "未找到目标页面 path=" + postcard.getPath() +
                        " group=" + postcard.getGroup() + " 做降级处理,5s后跳转降级页", Toast.LENGTH_LONG).show();
            }
            jumpDegradePage(context, postcard);
        }
    
        @Override
        public void init(Context context) {
            Log.e("buder", "init");
            //跳转目标activity未找到时,创建此降级服务实例,懒加载
        }
    
        private void jumpDegradePage(final Context context, final Postcard postcard) {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    ARouter.getInstance().build(ARouterConstants.DEGRADE)
                            .navigation(context);
                }
            }, 5 * 1000);
        }
    
    }

    Interceptor 拦截器

     

    @Interceptor(priority = 8, name = "test interceptor")
    public class TestInterceptor implements IInterceptor {
        @Override
        public void process(Postcard postcard, InterceptorCallback callback) {
            ...
            // No problem! hand over control to the framework
            callback.onContinue(postcard);  
            
            // Interrupt routing process
            // callback.onInterrupt(new RuntimeException("Something exception"));      
    
            // The above two types need to call at least one of them, otherwise it will not continue routing
        }
    
        @Override
        public void init(Context context) {
            // Interceptor initialization, this method will be called when sdk is initialized, it will only be called once
        }
    }

    拦截器的使用面向切面编程

     

    // 在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查
    // 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行  
    @Interceptor(name = "login", priority = 6)
    public class LoginInterceptorImpl implements IInterceptor {
        @Override
        public void process(Postcard postcard, InterceptorCallback callback) {
            String path = postcard.getPath();
            LogUtils.e(path);
            boolean isLogin = SPUtils.getInstance().getBoolean(RoutePath.SP_IS_LOGIN, false);
    
            if (isLogin) { // 如果已经登录不拦截
                callback.onContinue(postcard);
            } else {  // 如果没有登录
                switch (path) {
                    // 不需要登录的直接进入这个页面
                    case RoutePath.LOGIN_PATH:
                    case RoutePath.FIRST_PATH:
                        callback.onContinue(postcard);
                        break;
                    // 需要登录的直接拦截下来
                    default:
                        callback.onInterrupt(null);
                        break;
                }
            }
    
        }
    
        @Override
        public void init(Context context) {//此方法只会走一次
            LogUtils.e("路由登录拦截器初始化成功");
        }
    }
    

     

    //启动Activity
    ARouter.getInstance().build(RoutePath.SECOND_PATH)
                            .withString("msg", "ARouter传递过来的需要登录的参数msg")
                            .navigation(this,new LoginNavigationCallbackImpl());//第二个参数是路由跳转的回调
    

     

    public class LoginNavigationCallbackImpl  implements NavigationCallback {
        @Override //找到了
        public void onFound(Postcard postcard) {
    
        }
    
        @Override //找不到了
        public void onLost(Postcard postcard) {
    
        }
    
        @Override    //跳转成功了
        public void onArrival(Postcard postcard) {
    
        }
    
        @Override
        public void onInterrupt(Postcard postcard) {
            String path = postcard.getPath();
            LogUtils.v(path);
            Bundle bundle = postcard.getExtras();
            // 被登录拦截了下来了 
            // 需要调转到登录页面,把参数跟被登录拦截下来的路径传递给登录页面,登录成功后再进行跳转被拦截的页面
            ARouter.getInstance().build(RoutePath.LOGIN_PATH)
                    .with(bundle)
                    .withString(RoutePath.PATH, path)
                    .navigation();
        }
    }

    第一篇参考:https://www.jianshu.com/p/a57dd8c8f10e

    第二篇参考:https://www.jianshu.com/p/d5a83ccf1135

    项目代码:

    ARouter的基础使用 : https://github.com/buder-cp/DesignPattern/tree/master/ARounterDemo-master

    ARouter拦截器使用:https://github.com/buder-cp/DesignPattern/tree/master/ARouteLogin-master

    展开全文
  • ARouter基础

    2019-06-01 23:57:33
    ARouter基础介绍 目前组件化和模块化开发逐渐成为移动端开发的主要方式,方便调试,更快捷的开发,使得程序更容易扩展,ARouter的出现给我们提供了很大的便利,它是阿里巴巴自己研发的路由框架,主要解决组件间、...
  • ARouter 源码学习

    2018-04-10 17:32:59
    ARouter 源码学习 官方文档: Android平台页面路由框架ARouter 阿里巴巴Arouter github地址如下: ARouter gitHub 地址 ARouter我的学习注释GitHub地址: ARouter Arouter 组件化Demo: Android_...
  • ARouter 使用教程

    千次阅读 2018-07-13 19:34:51
    ARouter 是阿里开源的,可以看成是 Android 平台中对页面、服务提供路由功能的中间件。 ARouter 直接翻译过来就是路由,可以用来映射页面关系,实现跳转相关的功能。在 Android 中,常被用来进行组件化通讯。 ...
  • ARouter+MVVM

    2019-01-24 16:04:45
    该框架采用MVVM设计模式,并整合目前主流的Okhttp+RxJava+Retrofit网络框架和Glide图片加载框架,通过使用ARouter实现组件化,打造一个可以快速开发一个高质量、易维护的Android应用。
  • ARouter踩坑

    2020-03-24 18:34:47
    ARouter踩坑 1、页面跳转交互提示‘There is no route match the path’异常 1、编译的module需要依赖在‘主工程’下面 2、 Kotlin-Route参考 APT编译模式
  • ARouter基础踩坑demo

    2018-11-21 17:24:19
    ARouter基础踩坑demo,简单几个类,先让ARouter跑起来再说。
  • Arouter使用

    千次阅读 2019-06-29 15:09:25
    ARouter使用与原理 简单使用 1.添加依赖 在根目录下的build.gradle中添加如下代码 javaCompileOptions { annotationProcessorOptions { arguments = [moduleName :project.getName()] } } 在app下的build.gradle...
  • 组件化开发中,使用了ARouter作为路由组件,使用过程中出现了 'ARouter::: ARouter::There is no route match the path [/MyRouter2/ARouter3Activity] ' 原因 使用了@Route注解的module @Route(path = "/...
  • ARouter 梳理

    2019-10-22 16:17:58
    ARouter作为项目组件化的一个非常重要的工具,实现了很大的解耦 原理: 简单调用 @Route(path = "/test/activity1", name = "测试用 Activity") public class Test1Activity extends AppCompatActivity { path...
  • ARouter源码解析

    千次阅读 2019-07-09 23:13:33
    文章目录ARouter概述ARouter使用ARouter源码分析arouter-annotation注解arouter-compiler注解编译器arouter-api路由控制ARouter 初始化ARouter API跳转拦截器原理参考文档 ARouter概述 ARouter 是一个用于帮助 ...
  • Arouter源码分析xmind

    2020-10-20 12:38:23
    Arouter源码分析的xmind文件,直接在xmind打开。重要的类,接口,方法,一一列出,并给出详细介绍和分析。
  • 错误信息是这样子的,...Program type already present: com.alibaba.android.arouter.routes.ARouter$$Group$$arouter Message{kind=ERROR, text=Program type already present: com.alibaba.android.arouter.ro...
  • ARouter 引用

    2019-01-05 09:26:00
    1、功能简述 用于模块间解耦 2、module的gradle接入 android { defaultConfig { javaCompileOptions { annotationProcessorOptions { //ARouter def projectName = project.g...
  • 一种基于ARouter的使用封装方案,实现对ARouter的Retrofit2式使用
  • ArouterDemo.zip

    2019-07-05 19:35:06
    Arouter模块化开发示例,详情可以参考https://xiangzhihong.blog.csdn.net/article/details/94736340

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,976
精华内容 1,190
关键字:

arouter