Android之ARouter路由框架

今天,在此记录一下路由框架,在众多的路由框架中,阿里ARouter的给我一种亲切感。

ARouter是阿里巴巴开源的Android平台中对页面、服务提供路由功能的中间件,提倡的是简单且够用。

原生的路由方案的问题

  • 显式intent下,存在直接的类依赖,耦合严重
  • 隐式intent下,规则集中式管理,协作困难
  • 配置规则在Manifest中,扩展性差。
  • 跳转过程无法控制,使用StartActivity()就只能交给系统管理
  • 跳转失败下无法降级,抛出运营级异常

自定义路由组件目标

  • 通过URL索引解决类依赖
  • 通过分布式管理页面配置解决隐式intent中集中式管理Path问题
  • 实现整个路由过程,拥有良好的扩展性
  • 通过AOP的方式解决跳转过程无法控制问题
  • 同时能够提供非常灵活的降级方式

ARouter路由框架优势

Android之ARouter路由框架_第1张图片

  • 优势一:直接解析URL路由,解析参数并赋值到对应目标字段的页面中。
  • 优势二:支持多模块项目,因为现在很少有APP是单模块的项目,一般都是多模块单工程的,由不同的团队负责不同的模块开发,这时候支持多模块项目开发就显得尤为重要。
  • 优势三:支持InstantRun,目前很多路由框架并不支持InstantRun,而InstantRun是Google在AndroidStudio2.0阿尔法版本中提供的新功能,其类似于代码的日更新,其只不过面向的是开发过程,这样做可以在开发的过程中减少开发和编译的次数,可以简单地将代码修改即时地同步到APK中,从而可以大规模降低开发复杂度。
  • 优势四:允许自定义拦截器,ARouter是支持拦截器的,而拦截器其实就是AOP的实现,可以自定义多个拦截器解决一些面向行为编程上出现的问题。
  • 优势五:ARouter可以提供IoC容器,IoC其实就是控制反转,这一部分做过服务端开发的朋友可能比较了解,因为服务端开发经常用到的Spring框架能够提供的一个非常重要的能力就是控制反转。
  • 优势六:映射关系自动注册,在页面不是很多的小型APP上面,自动注册并不会体现出太大优势,但是对于大型APP而言,可能页面数量已经达到的几十个或者数百个,在这样的情况下,自动注册就显得非常重要了,因为不可能将每一个页面都通过代码的方式进行注册。
  • 优势七:灵活的降级策略,ARouter可以提供很多种降级策略供用户自行选择,而原生的路由方案存在无法灵活降级的问题,StartActivity()一旦失败将会抛出运营级异常。

ARouter的基本使用

添加依赖和配置(找最新的版本

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

dependencies {
    // 替换成最新版本, 需要注意的是api
    // 要与compiler匹配使用,均使用最新版可以保证兼容
    implementation 'com.alibaba:arouter-api:1.4.1'
    annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'
    ...
}

添加注解及初始化

在Application中ARouter初始化

private Boolean isDebug = true;

@Override
public void onCreate() {
    super.onCreate();
 
    if (isDebug) {
        // 这两行必须写在init之前,否则这些配置在init过程中将无效
        // 打印日志
        ARouter.openLog();    
        // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
        ARouter.openDebug();   
    }
    // 尽可能早,推荐在Application中初始化
    ARouter.init(instance); 
}

 在需要跳转的Activity上进行注解配置

// 在支持路由的页面上添加注解(必选)
// 这里的路径需要注意的是至少需要有两级,/xx/xx
@Route(path = "/**/ARouterActivity")
public class ARouterActivity extends AppCompatActivity {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_arouter);
    //....
}

 应用中的简单跳转

 ARouter.getInstance().build("/**/ARouterActivity").navigation();

 应用中携带参数的跳转

ARouter.getInstance().build("/**/ARouter2Activity")
                     .withString("id","01")
                     .withInt("age",18)
                     .navigation();

 在目标Activity中接受相关的参数

  • 每一个参数声明一个字段,并使用 @Autowired 标注
@Route(path = "/**/ARouterActivity")
public class ARouterActivity extends Activity {
    @Autowired
    public String id;
    @Autowired
    int age;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ARouter.getInstance().inject(this);

    // ARouter会自动对字段进行赋值,无需主动获取
    Log.d("param", id + age);
    }
}

 其中,下面这个代码是安卓组件接收方必须添加的代码。

 ARouter.getInstance().inject(this); 

ARouter的进阶使用

Activity之间传递自定义对象

// 自定义类
public class Test implements Serializable{
    public String id;

    //...
}
 //跳转至页面
ARouter.getInstance().build("/**/ARouterActivity")
       .withSerializable("test", test)
       .navigation();
//目标页面
@Autowired
Test test;

通过Url进行跳转

在AndroidManifest.xml中进行如下配置:


    
    
        

        

        
        
    

新建一个Activity用于监听Schame事件,之后直接把url传递给ARouter

@Route(path = "/**/SchameFilterActivity")
public class SchameFilterActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Uri uri = getIntent().getData();
    ARouter.getInstance().build(uri).navigation();
    finish();
    }
}

 设置拦截器

  • 多个拦截器会按优先级顺序依次执行
@Interceptor(priority = 2, 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初始化的时候调用该方法,仅会调用一次
    }
}

监听路由跳转结果

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

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

 获取Fragment的对象

// 获取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/**/fragment").navigation();

其他详细API

// 构建标准的路由请求
ARouter.getInstance().build("/**/main").navigation();

// 构建标准的路由请求,并指定分组
ARouter.getInstance().build("/**/main", "ap").navigation();

// 构建标准的路由请求,通过Uri直接解析
Uri uri;
ARouter.getInstance().build(uri).navigation();

// 构建标准的路由请求,startActivityForResult
// navigation的第一个参数必须是Activity,第二个参数则是RequestCode
ARouter.getInstance().build("/**/main", "ap").navigation(this, 5);

// 直接传递Bundle
Bundle params = new Bundle();
ARouter.getInstance()
    .build("/**/main")
    .with(params)
    .navigation();

// 指定Flag
ARouter.getInstance()
    .build("/**/main")
    .withFlags();
    .navigation();

// 获取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/**/fragment").navigation();
                    
// 对象传递
ARouter.getInstance()
    .withObject("key", new TestObj("Jack", "Rose"))
    .navigation();

// 觉得接口不够多,可以直接拿出Bundle赋值
ARouter.getInstance()
        .build("/home/main")
        .getExtra();

// 转场动画(常规方式)
ARouter.getInstance()
    .build("/test/activity2")
    .withTransition(R.anim.slide_in_bottom, R.anim.slide_out_bottom)
    .navigation(this);

// 转场动画(API16+)
ActivityOptionsCompat compat = ActivityOptionsCompat.
    makeScaleUpAnimation(v, v.getWidth() / 2, v.getHeight() / 2, 0, 0);

// ps. makeSceneTransitionAnimation 使用共享元素的时候,需要在navigation方法中传入当前Activity

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

// 使用自己的日志工具打印日志
ARouter.setLogger();

注意及混淆配置

初始化中的其他配置

ARouter.openLog(); // 开启日志
ARouter.openDebug(); // 使用InstantRun的时候,需要打开该开关,上线之后关闭,否则有安全风险
ARouter.printStackTrace(); // 打印日志的时候打印线程堆栈

路由中的分组概念

  • SDK中针对所有的路径(/**/activity)进行分组,分组只有在分组中的某一个路径第一次被访问的时候,该分组才会被初始化
  • 通过 @Route 注解指定分组,否则使用路径中第一段字符串(/*/)作为分组
  • 主动指定分组之后,应用内路由需要使用 ARouter.getInstance().build(path, group) 进行跳转,指定分组。
@Route(path = "/**/activity", group = "app")

添加混淆规则

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

# 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider

# 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现
-keep class * implements com.alibaba.android.arouter.facade.template.IProvider

 最后推荐文章:开源最佳实践:Android平台页面路由框架ARouter

 

你可能感兴趣的:(Android之开发框架)