ARouter 使用教程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details/81036719

ARouter 使用教程

简介

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 注解的方式
@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 的执行过程

ARouter.getInstance()
        .build(ARouterConstants.COM_ACTIVITY1)
        .navigation(this, new NavCallback() {

            @Override
            public void onFound(Postcard postcard) {
                Log.e(TAG, "onArrival: 找到了 ");
            }

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

            @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 方法。

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

Demo 地址

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏世界第一语言是java

Android全能开源项目xUtils3开发教程、简单封装

24540
来自专栏编程之路

羊皮书APP(Android版)开发系列(三)APP引导页启动控制类

12830
来自专栏刘望舒

探究RemoteViews的作用和原理

RmoteViews是一个能显示在其他进程的视图。同样也提供了一些基本的操作方法来修改视图的内容。

15710
来自专栏一个会写诗的程序员的博客

《Kotin 极简教程》第13章 使用 Kotlin 和 Anko 的Android 开发

Anko (https://github.com/Kotlin/anko) 是一个用 Kotlin 写的Android DSL (Domain-Specifi...

31630
来自专栏梦里茶室

Activity四种launchMode

总共有四篇关于Activity,task,launchMode的文章,可以在我的博客中查看,或者在文章底部点下一篇。 1.Standard 默认模式,多次实例化...

20190
来自专栏向治洪

Universal Image Loader for Android 使用实例

<span style="white-space:pre">      </span>// 1.获取ImageLoader实例         ImageLo...

244100
来自专栏Android-薛之涛

Android-Fragment

我们在创建Fragment的管理器的时候,会选择导入那个包下的FragmentManager.有app包下和v4包下的,这里我推荐用v4包的FragmentMa...

25830
来自专栏张善友的专栏

使用ASP.NET实现Model View Presenter(MVP)

作者:Billy McCafferty 翻译:张善友 原文地址:http://www.codeproject.com/useritems/ModelViewPr...

23680
来自专栏软件开发 -- 分享 互助 成长

WIFI环境下Android手机和电脑通信

前面已经写过一篇java实现最基础的socket网络通信,这篇和之前那篇大同小异,只是将客户端代码移植到手机中,然后获取本机IP的方法略有不同。 先讲一下本篇中...

39950
来自专栏cloudskyme

gwt之mvc4g

Mvc4g是一个简单的框架来实现的GWT应用程序的MVC模式。 主要思想 其主要思想是,以减轻开发人员的工作,以单独的视图从模型。该框架是一个XML文件,将允...

34260

扫码关注云+社区

领取腾讯云代金券