ARouter 源码解析(零) 基本使用

ARouter 源码解析(零) 基本使用

零、要解决的问题

在app的开发中,页面之间的相互跳转是最基本常用的功能。在Android中的跳转一般通过显式intent和隐式intent两种方式实现的,而Android的原生跳转方式会存在一些缺点:

  • 显式intent的实现方式,因为会存在直接的类依赖的问题,导致耦合严重;
  • 隐式intent的实现方式,则会出现规则集中式管理,导致协作变得困难;
  • 配置不够灵活,一般而言配置规则都是在Manifest中的;
  • 跳转过程无法控制,一旦使用了StartActivity()就无法插手其中任何环节了,只能交给系统管理;
  • 组件化开发时不容易实现解耦

一、Arouter简介

Arouter是alibaba推出的一个路由框架

github介绍:一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦

具有以下优点:

  • 更简便灵活的配置方式
  • 可以拦截跳转过程进行一些处理
  • 可监听/处理跳转结果
  • 容易实现跨模块的解耦
  • 支持从外部解析URL映射跳转到内部页面

二、Arouter的使用

2.1注解的使用

@Route 用来标记一个可以被路由的页面

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Route {

    //用来唯一标识一个路由节点
    String path();

    //用来将路由结点分组
    String group() default "";

    //略 名称,用来生成javadoc
    String name() default "";

    //对这个页面属性的设置
    int extras() default Integer.MIN_VALUE;

    //略 优先级
    int priority() default -1;
}

@Route标记目前可以用于标记Activity , IProvider的实现类(后文会讲)

@Interceptor 用来标记一个拦截器

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Interceptor {
    //拦截器的优先级
    int priority();

    //略 名称,用来生成javadoc
    String name() default "Default";
}
  • 拦截器可以用于对路由进行拦截、加参等
  • 每一个拦截器都是全局的,而拦截器的调用顺序取决于它们的优先级,优先级高的会先被调用
  • 如果一次路由在某个拦截器中被拦截,后面优先级较低的拦截器就不会接收到这次路由

@Autowired 用于标记需要自动填充的变量

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.CLASS)
public @interface Autowired {

    //标记变量对应的名字
    String name() default "";

    //如果为true,则这个变量为null时会抛出异常(不会检查基本类型)
    boolean required() default false;

    //略 描述这个属性
    String desc() default "";
}

Activity 中使用该注解标志的变量,会在页面被路由打开的时候自动赋予传递的参数值。

2.2 简单用法

Activity的简单跳转

根据path进行跳转

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

携带参数跳转

ARouter.getInstance().build("/test/1")
			.withLong("key1", 666L)
			.withString("key3", "888")
			.withObject("key4", new Test("Jack", "Rose"))
			.navigation();

for result

ARouter.getInstance().build("/home/main", "ap").navigation(this, requestCode);

获取Fragment

Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();

使用URL跳转

// 新建一个Activity用于监听Schame事件,之后直接把url传递给ARouter即可
public class SchameFilterActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);

	Uri uri = getIntent().getData();
	ARouter.getInstance().build(uri).navigation();
	finish();
    }
}
<activity android:name=".activity.SchameFilterActivity">
	
	<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>

自动填充参数

// 为每一个参数声明一个字段,并使用 @Autowired 标注
// URL中不能传递Parcelable类型数据,通过ARouter api可以传递Parcelable对象
@Route(path = "/test/activity")
public class Test1Activity extends Activity {
    @Autowired
    public String name;
    @Autowired
    int age;
    @Autowired(name = "girl") // 通过name来映射URL中的不同参数
    boolean boy;
    @Autowired
    TestObj obj;    // 支持解析自定义对象,URL中使用json传递

    @Override
    protected void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);
	    
	    ARouter.getInstance().inject(this);
    }
}

@Autowired只能在Activity或Fragment用来标记public的变量,变量可以为

传递自定义对象

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

拦截器

@Interceptor(priority = 8, name = "测试用拦截器")
public class TestInterceptor implements IInterceptor {
    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
	...
	callback.onContinue(postcard);  // 处理完成,交还控制权
	// callback.onInterrupt(null);      // 觉得有问题,中断路由流程

	// 以上两种至少需要调用其中一种,否则不会继续路由
    }

    @Override
    public void init(Context context) {
	// 拦截器的初始化,会在sdk初始化的时候调用该方法,仅会调用一次
    }
}

处理跳转结果

// 使用两个参数的navigation方法,可以获取单次跳转的结果
ARouter.getInstance().build("/test/1").navigation(this, new NavigationCallback() {
    @Override
    public void onFound(Postcard postcard) {
      ...
    }

    @Override
    public void onLost(Postcard postcard) {
	...
    }
});

降级策略

单独降级

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

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

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

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

全局降级

// 实现DegradeService接口,并加上一个Path内容任意的注解即可
@Route(path = "/xxx/xxx")
public class DegradeServiceImpl implements DegradeService {
  @Override
  public void onLost(Context context, Postcard postcard) {
	// do something.
  }

  @Override
  public void init(Context context) {

  }
}

注:单独降级优先于全局降级,使用单独降级后不会再调用全局降级

为页面声明更多信息

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

服务

暴露服务

// 声明接口,其他组件通过接口来调用服务
public interface HelloService extends IProvider {
    String 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) {

    }
}

发现服务

public class Test {
    @Autowired
    HelloService helloService;

    @Autowired(name = "/service/hello")
    HelloService helloService2;

    HelloService helloService3;

    HelloService helloService4;

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

    public void testService() {
	 // 1. (推荐)使用依赖注入的方式发现服务,通过注解标注字段,即可使用,无需主动获取
	 // Autowired注解中标注name之后,将会使用byName的方式注入对应的字段,不设置name属性,会默认使用byType的方式发现服务(当同一接口有多个实现的时候,必须使用byName的方式发现服务)
	helloService.sayHello("Vergil");
	helloService2.sayHello("Vergil");

	// 2. 使用依赖查找的方式发现服务,主动去发现服务并使用,下面两种方式分别是byName和byType
	helloService3 = ARouter.getInstance().navigation(HelloService.class);
	helloService4 = (HelloService) ARouter.getInstance().build("/service/hello").navigation();
	helloService3.sayHello("Vergil");
	helloService4.sayHello("Vergil");
    }
}

ARouter的分组概念

Root -> Group -> Activity

  • SDK中针对所有的路径(/test/1 /test/2)进行分组,
  • 可以通过 @Route 注解主动指定分组,否则使用路径中第一段字符串(/*/)作为分组
  • ARouter 初始化时只会初始化Root节点

你可能感兴趣的:(android)