ARouter路由框架介绍

ARouter路由框架介绍

一、为什么需要路由框架

由于最近对项目进行了组件化的设计,不同的组件之间涉及到跳转,所以产生了对路由框架的使用需求,所以选用了ARouter.

(1)原生的路由方案存在的问题

1.一般是通过显式intent和隐式intent两种方式实现的,而在显式intent的情况下,因为会存在直接的类依赖的问题,导致耦合非常严重;

2.在隐式intent情况下,则会出现规则集中式管理,导致协作变得非常困难。而且一般而言配置规则都是在Manifest中的,这就导致了扩展性较差。

3.使用原生的路由方案会出现跳转过程无法控制的问题,因为一旦使用了StartActivity()就无法插手其中任何环节了,只能交给系统管理,这就导致了在跳转失败的情况下无法降级,而是会直接抛出运营级的异常。

(2)为什么要用路由组件

使用自定义的路由组件就可以解决以上的一些问题,比如通过URL索引就可以解决类依赖的问题;通过分布式管理页面配置可以解决隐式intent中集中式管理Path的问题;自己实现整个路由过程也可以拥有良好的扩展性,还可以通过AOP的方式解决跳转过程无法控制的问题,与此同时也能够提供非常灵活的降级方式。还会涉及到其他的两个大方面:一方面是组件化,而另一方面就是Native和H5的问题。

1.组件化的问题:一旦一款APP达到一定体量的时候,业务就会膨胀得比较严重,而开发团队的规模也会越来越大,这时候一般都会提出组件化的概念。组件化就是将APP按照一定的功能和业务拆分成多个小组件,不同的组件由不同的开发小组来负责,这样就可以解决大型APP开发过程中的开发与协作的问题,将这些问题分散到小的APP中。目前而言组件化已经有非常多比较成熟的方案了,而自定义路由框架也可以非常好地解决整个APP完成组件化之后模块之间没有耦合的问题,因为没有耦合时使用原生的路由方案肯定是不可以的。

2.Native与H5的问题,因为现在的APP很少是纯Native的,也很少会有纯H5的,一般情况下都是将两者进行结合。这时候就需要非常便捷并且统一的跳转方案,因为在H5中是无法使用StartActivity()跳转到Native页面的,而从Native跳转到H5页面也只能通过配置浏览器的方式实现。

(3)路由框架的特点

分发:把一个URL或者请求按照一定的规则分配给一个服务或者页面来处理,这个流程就是分发,分发是路由框架最基本的功能,当然也可以理解成为简单的跳转。

管理:将组件和页面按照一定的规则管理起来,在分发的时候提供搜索、加载、修改等操作,这部分就是管理,也是路由框架的基础,上层功能都是建立在管理之上。

控制:就像路由器一样,路由的过程中,会有限速、屏蔽等一些控制操作,路由框架也需要在路由的过程中,对路由操作做一些定制性的扩展。

(4)ARouter的优点

1.直接解析URL路由,解析参数并赋值到对应目标字段的页面中。

2.支持多模块项目,因为现在很少有APP是单模块的项目,一般都是多模块单工程的,由不同的团队负责不同的模块开发,这时候支持多模块项目开发就显得尤为重要。

3.支持InstantRun,目前很多路由框架并不支持InstantRun,而InstantRun是Google在AndroidStudio2.0阿尔法版本中提供的新功能,其类似于代码的日更新,其只不过面向的是开发过程,这样做可以在开发的过程中减少开发和编译的次数,可以简单地将代码修改即时地同步到APK中,从而可以大规模降低开发复杂度。

4.允许自定义拦截器,ARouter是支持拦截器的,而拦截器其实就是AOP的实现。

5.ARouter可以提供IOC容器,IOC其实就是控制反转,并通过依赖注入实现。

6.映射关系自动注册,在页面不是很多的小型APP上面,自动注册并不会体现出太大优势,但是对于大型APP而言,可能页面数量已经达到的几十个或者数百个,在这样的情况下,自动注册就显得非常重要了,因为不可能将每一个页面都通过代码的方式进行注册。

7.灵活的降级策略,ARouter可以提供很多种降级策略供用户自行选择,而原生的路由方案存在无法灵活降级的问题,StartActivity()一旦失败将会抛出运营级异常。

IOC和AOP的简单理解:http://www.jianshu.com/p/cffa033d2eae

(5)典型应用场景

1.从外部URL映射到内部页面,以及参数传递与解析

2.跨模块页面跳转,模块间解耦

3.拦截跳转过程,处理登陆、埋点等逻辑

4.跨模块API调用,模块间解耦(注册ARouter服务的形式,通过接口互相调用)

二、ARounter的接入说明

(1)添加依赖和配置

 

android {

    defaultConfig {

         ...

         javaCompileOptions {

             annotationProcessorOptions {

                  arguments = [moduleName : project.getName() ]

             }

         }

    }

}

 

dependencies {

    // 替换成最新版本, 需要注意的是api

    // 要与compiler匹配使用,均使用最新版可以保证兼容

    compile'com.alibaba:arouter-api:x.x.x'

    annotationProcessor'com.alibaba:arouter-compiler:x.x.x'

    ...

}

(2)添加混淆规则(如果使用了Proguard)

-keep publicclass com.alibaba.android.arouter.routes.**{*;}

-keep class *implements com.alibaba.android.arouter.facade.template.ISyringe{*;}

(3)初始化SDK

ARouter.openLog();     // 打印日志

ARouter.openDebug();   // 开启调试模式(如果在InstantRun模式下运行,必须              开启调试模式!线上版本需要关闭,否则有安全风险)

ARouter.printStackTrace();// 打印日志的时候打印线程堆栈

ARouter.init(this);// 尽可能早,推荐在Application中初始化

三、ARounter的基本用法

(1)添加注解

// 在支持路由的页面上添加注解(必选)

// 这里的路径需要注意的是至少需要有两级,/xx/xx

@Route(path ="/test/activity")

public classYourActivity extend Activity {

  ...

}

(2)发起路由

1. 应用内简单的跳转

ARouter.getInstance()
        .build("/test/activity2")
        .navigation();

 

 2. 跳转并携带参数

ARouter.getInstance()
        .build("/kotlin/test")
        .withString("name", "老王")
        .withInt("age", 23)
        .withObject("object",new Object())
        .navigation();

 

 3. 旧版本转场动画跳转

ARouter.getInstance()
        .build("/test/activity2")
        .withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom)
        .navigation(this);

4.新版本转场动画跳转

if (Build.VERSION.SDK_INT >= 16) {
    ActivityOptionsCompat compat = ActivityOptionsCompat.
            makeScaleUpAnimation(v, v.getWidth() / 2, v.getHeight() / 2, 0, 0);

    ARouter.getInstance()
            .build("/test/activity2")
            .withOptionsCompat(compat)
            .navigation();
}

5. 带导航回调跳转

ARouter.getInstance()
        .build("/test/activity4")
        .navigation(this, new NavCallback() {
            @Override
            public void onArrival(Postcard postcard) {
            }

            @Override
            public void onInterrupt(Postcard postcard) {
            }
        });

6.Uri跳转并携带参数

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

7.通过Url跳转

Html的跳转链接标签

<a href="arouter://m.aliyun.com/test/activity2?key1=value1"></a>
<a href="http://m.aliyun.com/test/activity1"></a>

安卓Manifest文件中注册处理Html跳转链接的SchemeFilterActivity

<activity android:name=".SchemeFilterActivity">
    <!-- 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>
    <!-- App Links -->
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data
            android:host="m.aliyun.com"
            android:scheme="http"/>
        <data
            android:host="m.aliyun.com"
            android:scheme="https"/>
    </intent-filter>
</activity>

SchemeFilterActivity的onCreate方法中对uri进行分发

Uri uri = getIntent().getData();
ARouter.getInstance().build(uri).navigation(this, new NavCallback() {
    @Override
    public void onArrival(Postcard postcard) {
        finish();
    }
});

(3)获取参数(IOC)

通过在成员变量上加@Autowired标签。ARouter路由框架会依赖注入属性值。name为传参时的Key。

@Autowired(name = "boy")
boolean girl;

(4)设置拦截器(AOP)

1.自定义类实现

// 比较经典的应用就是在跳转过程中处理登陆事件,这样就不需要在目标页重复做登陆检查

// 拦截器会在跳转之间执行,多个拦截器会按优先级顺序依次执行

@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)使用服务(Interface)

这里说到的服务不是Android四大组件中的Service,这里的服务是服务端开发的概念,就是将一部分功能和组件封装起来成为接口,以接口的形式对外提供能力,所以在这部分就可以将每个功能作为一个服务,而服务的实现就是具体的业务功能

1.暴露服务

通过依赖注入解耦暴露服务

// 声明接口,其他组件通过接口来调用服务
public interface HelloService extends IProvider {
    void sayHello(String name);
}

 

// 实现接口
@Route(path = "/service/hello", name = "测试服务")
public class HelloServiceImpl implements HelloService {

    @Override
    public String sayHello(String name) {
        return "hello, " + name;
    }

    @Override
    public void init(Context context) {

    }
}

2.发现服务

通过依赖查找发现服务:主动去发现服务并使用。ARouter发现服务主要有两种方式,ByName和ByType。先看看这两种方式分别是怎么使用。ByName就是需要传递path路径来进行发现,ByType就是通过服务class来进行查找。

 

case R.id.navByName:
 ((HelloService)ARouter.getInstance().build("/service/hello").navigation()).sayHello("mike");
    break;
case R.id.navByType:
   ARouter.getInstance().navigation(HelloService.class).sayHello("mike");
    break;

那么为什么需要区分两种类型?因为在Java中接口是可以有多个实现的,通过ByType的方式可能难以拿到想要的多种实现,这时候就可以通过ByName的方式获取真实想要的服务。所以其实大多数情况是通过ByType的,如果有多实现的时候就需要使用ByName。

(推荐)通过依赖注入发现服务:

public class Test {
    //不设置name属性,会默认使用byType的方式发现服务(当同一接口有多个实现的时候,必须使用byName的方式发现服务)
    @Autowired
    HelloService helloService;
    // Autowired注解中标注name之后,将会使用byName的方式注入对应的字段
    @Autowired(name = "/service/hello")
    HelloService helloService2;

    HelloService helloService3;

    HelloService helloService4;

    public Test() {
        ARouter.getInstance().inject(this);
    }

    public void testService() {
        helloService.sayHello("Vergil");
        helloService2.sayHello("Vergil");
    }
}

 

 

(6)降级策略

ARouter提供的降级策略主要有两种方式,一种是通过回调的方式;一种是提供服务接口的方式。我们分别来看看两种方式的使用方法:

1.单独降级-回调的方式

这种方式在跳转失败的时候会回调NavCallback接口的onLost方法,对于降级策略主要实现感兴趣的onLost方法即可。

ARouter.getInstance().build("/xxx/xxx").navigation(this, new NavCallback() {
    @Override
    public void onFound(Postcard postcard) {
        Log.e("ARouter", "找到了");
    }

    @Override
    public void onLost(Postcard postcard) {
        Log.e("ARouter", "找不到了");
    }

    @Override
    public void onArrival(Postcard postcard) {
        Log.e("ARouter", "跳转完了");
    }

    @Override
    public void onInterrupt(Postcard postcard) {
        Log.e("ARouter", "被拦截了");
    }
});

 

2.全局降级-服务接口的方式

这种方式很简单,主要处理逻辑在内部

ARouter.getInstance().build("/xxx/xxx").navigation();

这种降级策略主要是实现服务接口DegradeService,就一个方法就是onLost,和上面的类似。

public interface DegradeServiceextends IProvider {

    /**
     * Router has lost.
     *
     * @param postcard meta
     */
    void onLost(Context context, Postcard postcard);
}

 

(7)更多功能

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

// 使用自己的日志工具打印日志
ARouter.setLogger();
// 构建标准的路由请求,startActivityForResult
// navigation的第一个参数必须是Activity,第二个参数则是RequestCode
ARouter.getInstance().build("/home/main", "ap").navigation(this, 5);
// 指定Flag
ARouter.getInstance()
        .build("/home/main")
        .withFlags()
        .navigation();
// 获取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
//获取原始的URI
String uriStr = getIntent().getStringExtra(ARouter.RAW_URI);

******************************END*********************************************

更详细的文档请见

GitHub:https://github.com/alibaba/ARouter

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值