转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/76165252

本文出自【赵彦军的博客】

一:什么是路由?

说简单点就是映射页面跳转关系的,当然它也包含跳转相关的一切功能。

二:为什么需要路由

Android系统已经给我们提供了api来做页面跳转,比如startActivity,为什么还需要路由框架呢?我们来简单分析下路由框架存在的意义:

  • 在一些复杂的业务场景下(比如电商),灵活性比较强,很多功能都是运营人员动态配置的,比如下发一个活动页面,我们事先并不知道具体的目标页面,但如果事先做了约定,提前做好页面映射,便可以自由配置。

  • 随着业务量的增长,客户端必然随之膨胀,开发人员的工作量越来越大,比如64K问题,比如协作开发问题。App一般都会走向组件化、插件化的道路,而组件化、插件化的前提就是解耦,那么我们首先要做的就是解耦页面之间的依赖关系。

  • 简化代码。数行跳转代码精简成一行代码。

  • 其他...

三:ARouter 简介

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

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

四:ARouter 优势

从 ARouter Github 了解到它的优势:

  • 支持直接解析标准URL进行跳转,并自动注入参数到目标页面中
  • 支持多模块工程使用
  • 支持添加多个拦截器,自定义拦截顺序
  • 支持依赖注入,可单独作为依赖注入框架使用
  • 支持InstantRun
  • 支持MultiDex(Google方案)
  • 映射关系按组分类、多级管理,按需初始化
  • 支持用户指定全局降级与局部降级策略
  • 页面、拦截器、服务等组件均自动注册到框架
  • 支持多种方式配置转场动画
  • 支持获取Fragment
  • 完全支持Kotlin以及混编

典型的应用:

  • 从外部URL映射到内部页面,以及参数传递与解析
  • 跨模块页面跳转,模块间解耦
  • 拦截跳转过程,处理登陆、埋点等逻辑
  • 跨模块API调用,通过控制反转来做组件解耦

五:ARouter 配置

  1. android {
  2. defaultConfig {
  3. ...
  4. javaCompileOptions {
  5. annotationProcessorOptions {
  6. arguments = [ moduleName : project.getName() ]
  7. }
  8. }
  9. }
  10. }
  11. dependencies {
  12. compile 'com.alibaba:arouter-api:1.2.1.1'
  13. annotationProcessor 'com.alibaba:arouter-compiler:1.1.2.1'
  14. }

api 的版本和 compiler 的版本号需要用最新的。最新的版本在 Github上可以找到。

六:ARouter 初始化

  1. public class MyApplication extends Application {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. ARouter.openLog(); // 打印日志
  6. ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
  7. ARouter.init( this ); // 尽可能早,推荐在Application中初始化
  8. }
  9. }

七:ARouter 注解发起路由

新建一个 Activity1 作为测试 ,在 Activity1 添加注解的代码如下:

  1. package com.router;
  2. import android.support.v7.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import com.alibaba.android.arouter.facade.annotation.Route;
  5. // 在支持路由的页面上添加注解(必选)
  6. // 这里的路径需要注意的是至少需要有两级,/xx/xx
  7. @Route(path = "/com/Activity1")
  8. public class Activity1 extends AppCompatActivity {
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_1);
  13. }
  14. }

在 MainActivity 的布局中添加一个按钮

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:tools="http://schemas.android.com/tools"
  4. android:layout_width="match_parent"
  5. android:layout_height="match_parent"
  6. tools:context="com.router.MainActivity">
  7. <TextView
  8. android:id="@+id/bt1"
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:text="应用内跳转"
  12. android:gravity="center"
  13. android:padding="10dp"
  14. android:background="#666666"
  15. />
  16. </LinearLayout>

MainActivity 里面的跳转逻辑是:

  1. public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.activity_main);
  6. findViewById( R.id.bt1).setOnClickListener( this );
  7. }
  8. @Override
  9. public void onClick(View v) {
  10. switch ( v.getId() ){
  11. case R.id.bt1 :
  12. //发起路由跳转
  13. ARouter.getInstance().build("/com/Activity1").navigation();
  14. break;
  15. }
  16. }
  17. }

效果图如下:

如果你想实现像 startActivityForResult() 功能,可以这样使用:

  1. navigation(Activity mContext, int requestCode)

具体使用如下:

  1. ARouter.getInstance()
  2. .build("/com/Activity1")
  3. .navigation( this , 100 );

如果 Path 路径不正确会发生什么,我们来测试一下,现在我们把路由操作改为

  1. ARouter.getInstance().build("/com/Test").navigation();

效果如下:

可以看到有一个 Toast 提示我们找不到 "/com/Test" 路径,我们来看看源码

通过源码我们可以看到在 debug 状态下,当找不到路由路径目标是,会有 Toast 提示。

八:监听路由过程

在路由跳转的过程中,我们可以监听路由的过程,只需要使用:

  1. navigation(Context context, NavigationCallback callback)

NavigationCallback 的源码如下:

  1. public interface NavigationCallback {
  2. /**
  3. * Callback when find the destination.
  4. * 找到了
  5. * @param postcard meta
  6. */
  7. void onFound(Postcard postcard);
  8. /**
  9. * Callback after lose your way.
  10. * 找不到了
  11. * @param postcard meta
  12. */
  13. void onLost(Postcard postcard);
  14. /**
  15. * Callback after navigation.
  16. * 跳转完了
  17. * @param postcard meta
  18. */
  19. void onArrival(Postcard postcard);
  20. /**
  21. * Callback on interrupt.
  22. * 被拦截了
  23. * @param postcard meta
  24. */
  25. void onInterrupt(Postcard postcard);
  26. }

具体使用如下

  1. ARouter.getInstance()
  2. .build("/com/Activity1")
  3. .navigation(this, new NavCallback() {
  4. @Override
  5. public void onFound(Postcard postcard) {
  6. Log.e("zhao", "onArrival: 找到了 ");
  7. }
  8. @Override
  9. public void onLost(Postcard postcard) {
  10. Log.e("zhao", "onArrival: 找不到了 ");
  11. }
  12. @Override
  13. public void onArrival(Postcard postcard) {
  14. Log.e("zhao", "onArrival: 跳转完了 ");
  15. }
  16. @Override
  17. public void onInterrupt(Postcard postcard) {
  18. Log.e("zhao", "onArrival: 被拦截了 ");
  19. }
  20. });

九:发起路由并且传递参数

  1. ARouter.getInstance()
  2. .build("/com/Activity1")
  3. .withString( "key" , "123") //参数:键:key 值:123
  4. .navigation();

ARouter 提供了丰富大量的参数类型,供我们选择。

  1. //基础类型
  2. .withString( String key, String value )
  3. .withBoolean( String key, boolean value)
  4. .withChar( String key, char value )
  5. .withShort( String key, short value)
  6. .withInt( String key, int value)
  7. .withLong( String key, long value)
  8. .withDouble( String key, double value)
  9. .withByte( String key, byte value)
  10. .withFloat( String key, float value)
  11. .withCharSequence( String key, CharSequence value)
  12. //数组类型
  13. .withParcelableArrayList( String key, ArrayList<? extends Parcelable > value)
  14. .withStringArrayList( String key, ArrayList<String> value)
  15. .withIntegerArrayList( String key, ArrayList<Integer> value)
  16. .withSparseParcelableArray( String key, SparseArray<? extends Parcelable> value)
  17. .withCharSequenceArrayList( String key, ArrayList<CharSequence> value)
  18. .withShortArray( String key, short[] value)
  19. .withCharArray( String key, char[] value)
  20. .withFloatArray( String key, float[] value)
  21. .withCharSequenceArray( String key, CharSequence[] value)
  22. //Bundle 类型
  23. .with( Bundle bundle )
  24. //Activity 跳转动画
  25. .withTransition(int enterAnim, int exitAnim)
  26. //其他类型
  27. .withParcelable( String key, Parcelable value)
  28. .withParcelableArray( String key, Parcelable[] value)
  29. .withSerializable( String key, Serializable value)
  30. .withByteArray( String key, byte[] value)
  31. .withTransition(int enterAnim, int exitAnim)

十:路由分组

在前面我们讲到在对 Activity1 做注解的时候,用到了

  1. @Route(path = "/com/Activity1")
  2. public class Activity1 extends AppCompatActivity {
  3. }

在 path 这个字符串里面,"com" 就代表组的标识;“Activity1" 代表是 Activity1 类的具体表示。组的标识和类的标识都可以自己定义的,需要记住的是组标识和类标识之间用斜杠来区分 '''' .

什么是组?

这里就需要提下,ARouter框架是分组管理,按需加载。提起来很高深的样子呢!其实解释起来就是,在编译期框架扫描了所有的注册页面/服务/字段/拦截器等,那么很明显运行期不可能一股脑全部加载进来,这样就太不和谐了。所以就分组来管理,ARouter在初始化的时候只会一次性地加载所有的root结点,而不会加载任何一个Group结点,这样就会极大地降低初始化时加载结点的数量。比如某些Activity分成一组,组名就叫test,然后在第一次需要加载组内的某个页面时再将test这个组加载进来。

测试一下:

  1. ARouter.getInstance()
  2. .build("/com/Activity1")
  3. .navigation(this, new NavCallback() {
  4. @Override
  5. public void onArrival(Postcard postcard) {
  6. String group = postcard.getGroup();
  7. Log.e("zhao", "分组是: " + group);
  8. }
  9. });

结果是

  1. 07-27 17:32:17.880 19449-19449/com.router E/zhao: 分组是: com

ARouter 默认情况下的分组就是第一个 / / 之间的内容。

自定义分组:

创建 CustomGroupActivity 并且添加 注解,并且指定路由分组。自定义分组的就是在原来的注解上添加 group 字段, 如下所示。

  1. @Route(path = "/com/CustomGroupActivity" , group = "customGroup")
  2. public class CustomGroupActivity extends AppCompatActivity {
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_custom_group);
  7. }
  8. }

自定义分组,发起路由:第二个参数就是路由的分组

  1. build(String path, String group)

具体实现如下所示:

  1. ARouter.getInstance().build("/com/CustomGroupActivity", "customGroup").navigation();

十一:Fragment 路由

创建 Fragment 类,并且添加路由注解

  1. @Route(path = "/com/TestFragment")
  2. public class TestFragment extends Fragment {
  3. @Override
  4. public View onCreateView(LayoutInflater inflater, ViewGroup container,
  5. Bundle savedInstanceState) {
  6. View view = inflater.inflate(R.layout.fragment_test, container, false);
  7. return view ;
  8. }
  9. }

获取 Fragment 实例

  1. Fragment fragment = (Fragment) ARouter.getInstance().build( "/com/TestFragment" ).navigation();

十二:URL 跳转

web url 跳转流程图

创建URL 中间跳转页

创建 URLReceiveActivity

  1. /**
  2. * URL 中转Activity
  3. */
  4. public class URLReceiveActivity extends AppCompatActivity {
  5. @Override
  6. protected void onCreate(Bundle savedInstanceState) {
  7. super.onCreate(savedInstanceState);
  8. setContentView( R.layout.activity_url_receive );
  9. //对URI 数据分发
  10. Uri uri = getIntent().getData();
  11. ARouter.getInstance().build(uri).navigation(this, new NavCallback() {
  12. @Override
  13. public void onArrival(Postcard postcard) {
  14. finish();
  15. }
  16. });
  17. }
  18. }

URLReceiveActivity 添加注册

  1. <activity android:name=".URLReceiveActivity">
  2. <!-- Schame -->
  3. <intent-filter>
  4. <data
  5. android:host="zhaoyanjun"
  6. android:scheme="arouter" />
  7. <action android:name="android.intent.action.VIEW" />
  8. <category android:name="android.intent.category.DEFAULT" />
  9. <category android:name="android.intent.category.BROWSABLE" />
  10. </intent-filter>
  11. </activity>

这里面的 host 、scheme 字段很重要。点击 url 会根据这两个字段会调起本地的 Activity 。

下面是一段 HTML 片段

  1. <h2>1:URL普通跳转</h2>
  2. <p><a href="arouter://zhaoyanjun/com/URLActivity1">arouter://zhaoyanjun/com/URLActivity1 </a>
  3. </p>
  4. <h2>2:URL普通跳转携带参数</h2>
  5. <p>
  6. <a href="arouter://zhaoyanjun/com/URLActivity2?name=alex&age=18&boy=true&high=180&obj=%7b%22name%22%3a%22jack%22%2c%22id%22%3a666%7d">arouter://zhaoyanjun/test/URLActivity2?name=alex&age=18&boy=true&high=180&obj={"name":"jack","id":"666"}
  7. </a>
  8. </p>

注意 a 标签里面的 arouter://zhaoyanjun 分别代表着 scheme 、host ;/com/URLActivity1 就是目标 Activity 的注解。

如果需要接收 URL 中的参数,需要在 Activity 调用自动注入初始化方法;

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

需要注意的是,如果不使用自动注入,那么可以不写 ARouter.getInstance().inject(this),但是需要取值的字段仍然需要标上 @Autowired 注解,因为 只有标上注解之后,ARouter才能知道以哪一种数据类型提取URL中的参数并放入Intent中,这样您才能在intent中获取到对应的参数

具体的代码如下:

  1. @Route(path = "/com/URLActivity2")
  2. public class URLActivity2 extends AppCompatActivity{
  3. private TextView textView;
  4. @Autowired
  5. String name;
  6. @Autowired
  7. int age;
  8. @Autowired
  9. boolean boy;
  10. @Autowired
  11. int high;
  12. @Autowired
  13. String obj ;
  14. @Override
  15. protected void onCreate(Bundle savedInstanceState) {
  16. super.onCreate(savedInstanceState);
  17. ARouter.getInstance().inject(this);
  18. setContentView(R.layout.activity_url2);
  19. textView = (TextView) findViewById(R.id.tv);
  20. //解析参数
  21. Bundle bundle = getIntent().getExtras();
  22. String name1 = bundle.getString("name");
  23. textView.setText("参数是: " + "name: " + name + " age: " + age
  24. + " boy: " + boy + " name1: " + name1 + " obj: " + obj.toString() );
  25. }
  26. }

效果图如下:

十三:暴露服务

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

我们先自定义一个接口 IService 并且继承 IProvider 。IService 接口里面有一个 sayHello() 方法,具体代码如下。

  1. public interface IService extends IProvider {
  2. void sayHello(Context context );
  3. }

先定义一个 IService 的实现类 MyService 并且添加注解,代码如下

  1. @Route(path = "/service/hello", name = "测试服务")
  2. public class MyService implements IService {
  3. @Override
  4. public void sayHello( Context context ) {
  5. Toast.makeText( context , "hello", Toast.LENGTH_SHORT).show();
  6. }
  7. @Override
  8. public void init(Context context) {
  9. }
  10. }

发现服务,首先定义服务对象,并且添加注解,我们不需要知道接口的具体实现类。

  1. @Autowired(name = "/service/hello")
  2. IService service;

然后添加注解初始化,自动赋值。

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

最后我们调用 service 里面的 sayHello() 方法。

  1. service.sayHello(this);

效果图如下:

发现服务这个功能的特点在于,我们只需要知道接口,不需要关心接口的实现类,很好了实现了解耦。

十四:其他

  • 关闭路由,这个操作慎用
  1. ARouter.getInstance().destroy();

十五:混淆说明

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

总结

所有的代码都上传至Github: https://github.com/zyj1609wz/Router

参考资料

ARouter解析一:基本使用及页面注册源码解析

ARouter解析二:页面跳转源码分析


个人微信号:zhaoyanjun125 , 欢迎关注

Android 路由框架ARouter最佳实践的更多相关文章

  1. Android路由框架-ARouter详解

    文章大纲 一.页面路由基本介绍1.什么是页面路由2.为什么要使用页面路由二.页面路由框架ARouter介绍1.常用功能介绍2.常见应用场景三.源码下载四.参考文章   一.页面路由基本介绍 1.什么是 ...

  2. Google Developing for Android 二 - Memory 最佳实践 // lightSky‘Blog

    Google Developing for Android 二 - Memory 最佳实践   |   分类于 Android最佳实践 原文:Developing for Android, II Th ...

  3. Android和PHP开发最佳实践

    Android和PHP开发最佳实践 <Android和PHP开发最佳实践>基本信息作者: 黄隽实丛书名: 移动应用开发技术丛书出版社:机械工业出版社ISBN:9787111410508上架 ...

  4. 严选 Android 路由框架优化(上篇)

    0 背景 早前严选 Android 工程,使用原生 Intent 方式做页面跳转,为规范参数传递,做了编码规范,使用静态方法的方式唤起 Activity public static void star ...

  5. 组件化框架设计之阿里巴巴开源路由框架——ARouter原理分析(一)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 背景 当项目的业务越来越复杂,业务线越来越多的时候,就需要按照业 ...

  6. Google Developing for Android 三 - Performance最佳实践

    Google Developing for Android 三 - Performance最佳实践 发表于 2015-06-07   |   分类于 Android最佳实践 原文 Developing ...

  7. atitit. 统计功能框架的最佳实践(1)---- on hibernate criteria

    atitit. 统计功能框架的最佳实践(1)---- on hibernate criteria 1. 关键字 1 2. 统计功能框架普通有有些条件选项...一个日期选项..一个日期类型(日,周,月份 ...

  8. 开源调度框架Quartz最佳实践

    开源调度框架Quartz最佳实践 Quartz是一个Java调度框架,当前的最新版本为2.2.1. 以Quartz 2.2.1版为例,Quartz最佳实践(用于生产系统)总结如下: 1.跳过更新检查Q ...

  9. 严选 Android 路由框架优化(下篇)

    3 router 框架优化 3.1 apt 生成代码量过大问题优化 思考框架本身,其实可以发现仅有 router 映射表是需要根据注解编译生成的,其他的全部代码都是固定代码,完全可以 sdk 中直接编 ...

随机推荐

  1. Linux 学习笔记_12_文件共享服务_3_NFS网络文件服务

    NFS网络文件服务 NFS---- Network File System 用于UNIX/Linux[UNIX类操作系统]系统间通过网络进行文件共享,用户可以把网络中NFS服务器提供的共享目录挂载到本 ...

  2. Dynamics Crm2011 Removes an option from an Option Set control

    应用场景:OptionSet中有N个option值,特定的条件下需要去除某些option的显示,例如在某个条件下我要红框中的两个option不显示 var purchasetype= Xrm.Page ...

  3. spring揭秘 读书笔记 一 IoC初探

    本文是王福强所著<<spring揭秘>>一书的读书笔记 ioc的基本概念 一个例子 我们看下面这个类,getAndPersistNews方法干了四件事 1 通过newsList ...

  4. libevent之eventop

    在之前博文libevent之Reactor模式中,我们知道Reactor模式中一个重要的组件就是事件多路分发机制(event demultiplexer).而在libevent中,对事件多路分发机制的 ...

  5. uGUI使用代码动态添加Button.OnClick()事件(Unity3D开发之十二)

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/42705885 ...

  6. R12.2. Start and Stop Procedure

    R12.2. Start and Stop Procedure   Leave a comment Individual Components:  Application(Middle Tier) $ ...

  7. Java进阶(十三)servlet监听器

    servlet监听器 Listener是Servlet的监听器,它可以监听客户端的请求.服务端的操作等.通过监听器,可以自动激发一些操作,比如监听在线的用户的数量.当 增加一个HttpSession时 ...

  8. LIRe 源代码分析 3:基本接口(ImageSearcher)

    ===================================================== LIRe源代码分析系列文章列表: LIRe 源代码分析 1:整体结构 LIRe 源代码分析 ...

  9. overridePendingTransition的简介

     1 Activity的切换动画指的是从一个activity跳转到另外一个activity时的动画. 它包括两个部分:一部分是第一个activity退出时的动画:另外一部分时第二个activity ...

  10. JSP 知识基本

    from:http://blog.csdn.net/caipeichao2/article/details/38589293 more:http://www.2cto.com/kf/web/jsp/4 ...