ARouter基本使用详情

Posted microhex

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ARouter基本使用详情相关的知识,希望对你有一定的参考价值。

  由于公司项目进行了拆分,我司就用上了阿里的这个ARouter框架。对于为啥使用这个框架,我相信很多人知道原因,借用阿里的云栖社区的一段话:我们所使用的原生路由方案一般是通过显式intent和隐式intent两种方式实现的,而在显式intent的情况下,因为会存在直接的类依赖的问题,导致耦合非常严重;而在隐式intent情况下,则会出现规则集中式管理,导致协作变得非常困难。而且一般而言配置规则都是在Manifest中的,这就导致了扩展性较差。除此之外,使用原生的路由方案会出现跳转过程无法控制的问题,因为一旦使用了StartActivity()就无法插手其中任何环节了,只能交给系统管理,这就导致了在跳转失败的情况下无法降级,而是会直接抛出运营级的异常。这时候如果考虑使用自定义的路由组件就可以解决以上的一些问题,比如通过URL索引就可以解决类依赖的问题;通过分布式管理页面配置可以解决隐式intent中集中式管理Path的问题;自己实现整个路由过程也可以拥有良好的扩展性,还可以通过AOP的方式解决跳转过程无法控制的问题,与此同时也能够提供非常灵活的降级方式。那么我就总结一下ARouter的使用方法。

  其实下文所有的描述都可以在ARouer的文档中查找,但是个人感觉文档有些地方写的还是比较蛋疼,很多概念感觉只是一笔带过。结合自己踩的坑,写下自己的使用方法。

配置:

build.grade中配置:


android 
	...
    defaultConfig 
        ...
        javaCompileOptions 
            annotationProcessorOptions 
                arguments = [moduleName: project.getName()]
            
        
    

dependencies 
  compile 'com.alibaba:arouter-api:1.2.2'
  annotationProcessor 'com.alibaba:arouter-compiler:1.1.3'

使用:

初始化:

一般在Application.onCreate()的初始化:

if (isDebug())            // 这两行必须写在init之前,否则这些配置在init过程中将无效
    ARouter.openLog();     // 打印日志
    ARouter.openDebug();   
    // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)

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

####添加注解:
对于你需要路由到的Activity,需要使用Route注解,对于Route注解,必须初始化path路劲,而且path必须至少存在两级以上,即像这样 /xx/xx …,例子如下:

@Route(path = "/simple/simple1Activity")
public class Simple1Activity extends AppCompatActivity 

路由该Activity时,使用一下方法:

ARouter.getInstance().build("/simple/simple1Activity").navigation();

最基本的路由方案已经好了,现在编译就可以使用了。没错,就是这么简单。

####路由传递参数:
上面简单的路由已经完成了,如果需要需要想目标Activity传递参数呢?可以看下面的例子,先看路由命令:

 ARouter.getInstance().
                build("/simple/simpledata").
                withString("name","zhangsan").
                withInt("age",18).
                withParcelable("test",new TestParcelable("Tom",12)).
                navigation();

那么目标Activity呢?源码如下:

@Route(path = "/simple/simpledata")
public class SimpleDataActivity extends AppCompatActivity 

    TextView tv ;

    @Autowired()
    String name ;

    @Autowired(name = "age")
    int age ;

    @Autowired
    TestParcelable test ;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple_data);

        //inject
        ARouter.getInstance().inject(this);

        tv = (TextView) findViewById(R.id.id_tv);
        tv.setText("name:" + name +",age:" + age  + ",test:"+test);
    

我们需要为参数声明字段,并用@Autowired注解表示,@Autowired可以填写name标识,依次来映射URL中的不同参数;最后使用ARouter.getInstance().inject(this);方法来inject来初始化@Autowired注解的字段。结果就就不贴了,这个比较简单。

startActivityForResult方案:

很多时候我们路由到目标Activity,然后需要返回Result,即我们通常重写的startActivityForResult&onActivityResult方法。使用ARouter也很简单,如下:

ARouter.getInstance().build("/simple/simpledata").
                withString("name","zhangsan").
                withInt("age",18).
                withParcelable("test",new TestParcelable("Tom",12)).
                navigation(this,100);

只需要在navigation()方法中添加参数了,第一个参数必须是Activity,第二个参数就是我们的requestCode。

获取路由结果:

当我们每一次进行路由时,可能需要知道我们的路由是否被接受,是否丢失,是否被拦截器拦截,那么可以使用navigation()方法的重载函数:

ARouter.getInstance().build("/test/simple_interceptor").navigation(this, new NavCallback() 
            @Override
            public void onArrival(Postcard postcard)   //路由到达之后调用
                Log.d("MainActivity" , "onArrival : " + postcard.getPath());
            

            @Override
            public void onInterrupt(Postcard postcard)   //路由被拦截时调用
                Log.d("MainActivity" , "onInterrupt : " + postcard.getPath());
            

            @Override
            public void onLost(Postcard postcard)    //路由被丢失时调用
                Log.d("MainActivity" , "onLost : " + postcard.getPath());
            

            @Override
            public void onFound(Postcard postcard)   //路由目标被发现时调用
                Log.d("MainActivity" , "onLost : " + postcard.getPath());
            
        );

interceptor拦截器:

ARouter也添加了拦截器模式,拦截器有很多用处,比如路由到目标页面时,检查用户是否登录,检查用户权限是否满足,如果不满足,则路由到相应的登录界面或者相应的路由界面。ARouter的拦截器比较奇葩,只需要实现IInterceptor接口,并使用@Interceptor注解即可,并不需要注册就能使用。当然这也有了它的坏处,就是每一次路由之后,都会经过拦截器进行拦截,显然这样程序的运行效率就会降低。Interceptor可以定义多个,比如定义登录检查拦截器,权限检查拦截器等等,拦截器的优先级使用priority定义,优先级越大,越先执行。拦截器内部使用callback.onContiune()/callback.onInterrupt(),前者表示拦截器任务完成,继续路由;后者表示终止路由。例子:

@Interceptor(priority = 4)
public class TestInterceptor implements IInterceptor 

    @Override
    public void process(final Postcard postcard, final InterceptorCallback callback) 
        Log.d("interceptor",postcard.getPath() + ".." + postcard.getGroup());
		
	//这里进行逻辑处理	
	//callback.onContinue(postcard);
	or
	//callback.onInterrupt(postcard)
    

    @Override
    public void init(Context context) 
        Log.d("init",TestInterceptor.class.getSimpleName() + " has been inited");
    

而这里的逻辑判断,比如我要判断用户是否登录,如果登录了,则放行,否则进行登录路由。

 if(Constant.isLogin()) 
    callback.onContinue(postcard);
  else 
    callback.onInterrupt(null);
    ARouter.getInstance().build("/router/login").navigation();
  

当然了,如果有些路由希望不经过任何的拦截器,ARouter很贴心的给出了一个绿色通道函数供我们使用,使用greenChannel()时所有的Interceptor将失效:

ARouter.getInstance().build("/test/simple_interceptor").greenChannel().navigation();

自定义全局降级策略:

这个说的比较高大上,通俗一点讲,就是如果我们的app全是Native写的,如果有一天我们的隐性的Intent不能匹配所有的Activity时,我们的Activity就会报错,更坏的结果就是会导致崩溃。而降级策略就是为了解决这个问题的,如果不存在这个路由,那么我们可以集中处理这些错误,比如返回到主页面,或者也可以返回一个错误页面。降级策略需要实现DegradeService接口,并且使用@Route注解来表明那些哪些路由需要被处理。降级策略可以有多个。举个例子:

@Route(path = "/user/*")
public class LoginDegradeServiceImpl implements DegradeService 

    Context mContext;

    @Override
    public void onLost(Context context, Postcard postcard) 
	    //
	    LogUtils.d("onLost:" + postcard);
        ARouter.getInstance().build("/router/login").navigation();
    

    @Override
    public void init(Context context) 
        this.mContext = context ;
    

这个是定义登录时,如果使用了错误的路由方式,将路由到登录界面。注意到path="/user/**",表明只要是一次级的user的错误路由,都会传递到这里。因为项目会存在很多模块,这里定义的"/user/*" 只是识别用户模块的,而影响其他模块。

服务管理:

个人感觉这个功能比较鸡肋,项目中目前没有用到过,但是ARouter还是提供了相应的方法,这里还是简单介绍一下。这里的服务不是Android四大组件的所说的那种Service,更贴切的说,应该是一种接口,通过ARouter依赖注入找到其实现类,然后使用接口中的方法。
服务接口需要继承IProvider:

public interface HelloService  extends IProvider
    void sayHello(String name);    

获取实现类,并@Route绑定path:


@Route(path = "/service/helloservice")
public class HelloServiceImpl implements HelloService 

    Context mContext;

    @Override
    public void sayHello(String name) 
        Toast.makeText(mContext, "hello " + name, Toast.LENGTH_SHORT).show();
    

    @Override
    public void init(Context context) 
        this.mContext = context ;
        Log.d("HelloServiceImpl" , "the context is " + mContext);
    

那么在使用时,可以有两种方法,一种是通过Name获取,一种是通过Type获取:
通过Name获取:

 ((HelloService)ARouter.getInstance().build("/service/helloservice").navigation()).sayHello("micro name ");

而通过Type获取时:

ARouter.getInstance().navigation(HelloService.class).sayHello("micro type ");

通过上述两种方案,都可以调用HelloService接口,并执行sayHello方法。个人感觉并没什么卵用,我需要这种实现方案到底要干什么呢? 个人现在的项目还用不上这种方式吧。

总结:

  项目中基本上就是用到了这些了,当然还有一些像转场动画,分组的概念,由于暂时项目中并没有使用到,所以就不总结了。基本上对ARouter的使用方式也就这么多了。

以上是关于ARouter基本使用详情的主要内容,如果未能解决你的问题,请参考以下文章

ARouter的原理

Arouter之API原理解析

Android-ARouter原理解析

组件化解耦 | 浅析ARouter路由发现原理与简单实践

ARouter踩坑指南

ARouter踩坑指南