4

ARouter 在多 module 项目中实战

 2 years ago
source link: https://segmentfault.com/a/1190000040843076
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

ARouter 在多 module 项目中实战

本文已首发微信公众号「code小生」,大家可以搜索关注,专注安卓技术分享。

本文仅作案例演示,方便学习和掌握基础知识,不进行源码级别的探究。下面先明确一下能实现的功能和用到的技术点以及环境。

  • 多module工程,有baseLib和主APP以及多业务module
  • 多module,实现某个module可独立运行
  • 多module之间跳转,使用ARouter框架
  • ARouter拦截器使用
  • Android Studio4.1.2
  • 语言:Java
  • 手机:三星A6s Android10

路由应用场景

安卓的项目结构发展越来越倾向于多模块,而模块间的跳转如果使用原生方式(Intent跳转),那么会随着项目的发展壮大,最终导致错综复杂的import xxx,从而给维护带来很大的麻烦,如下图这样:

不使用路由的多模块

黑色线条: 表示依赖关系,有了依赖,就可以在当前模块引用其他模块的类,就可以使用Intent 跳转。<br/>
蓝色线条: 表示从app模块要跳转login,live,work模块的某个页面,那么必须依赖对应模块才可以引用到相关类,从而实现跳转。<br/>
红色线条: 业务需要,从work模块可以直接进入直播间,那么work模块就必须依赖live模块;反之亦然。<br/>
绿色线条: 当用户没有登录,或者登录状态失效,亦或者账号在别处登录了,那么需要从当前模块跳转到login模块,所以其他基础模块都要依赖login模块。

这样随着项目功能的拓展,带来的问题就很明显了。

ARouter的出现,就很好的解决了这个问题,官网地址:https://github.com/alibaba/ARouter/ ,其功能很强大,对于多模块的项目,无论是否组件化,都很好的解决了相互依赖和跳转带来的维护成本。如下简易图:

使用路由的多模块

黑色线条: 表示依赖关系,这里的依赖主要是解决资源共用问题,而不是跳转。如果用不到baselib中的资源,那么无需依赖。<br/>
其他虚线条: 表示无需相互依赖,就可以实现页面跳转和通信,这就是路由的强大之处。<br/>

工程 Module 配置

我这里命名为MyArouter,然后分别 new Module:baseLibcirclehome 选择 Android Library 类型,编译完成如下图,则为正常状态;

添加依赖关系

win 系统通过快捷键 Ctrl+Shift+Alt+S 调出 Project Structure 面板,当然你也可以通过点击菜单栏的File->Project Structure 来打开这个面板。

Project Structure

如图选择不同的模块,添加依赖模块即可,我这里的依赖是这样的:

  • app模块依赖:baseLibcirclehome
  • baseLib模块:不依赖任何功能模块
  • circle模块依赖:baseLib
  • home模块依赖:baseLib

模块说明

  • baseLib:项目的公共基础模块,一般可以包括共用的工具类、公共资源、公共代码片段、共用三方引用等等可以放在这里,这样做可以避免很多的重复代码、提高代码的可阅读性和程序的易维护。
  • app:是整个项目的宿主模块,也就是说该模块的优先级是高于其他功能模块的,因为程序的主入口是这里。
  • 其他模块,都是按照业务功能来划分,负责具体的业务。

工程 ARouter 配置

第一步:baseLib模块配置

打开baseLib下的build.gradle文件,在dependencies下添加如下代码

api 'com.alibaba:arouter-api:1.5.2'

接着在baseLib下新建 BaseApplication 类,完整代码如下:

public class BaseApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        initRouter(this);
    }

    public static void initRouter(Application application) {
        if (BuildConfig.DEBUG) {
            ARouter.openLog();
            ARouter.openDebug();
        }
        ARouter.init(application);
    }

}

然后新建类ARouterPath,该类的功能是提供统一的路由跳转页面路径,也就是ARouter中的path值;

public class ARouterPath {

    public static final String CIRCLE_CIRCLE="/circle/home";

}

第二步:其他模块配置

依次在appcirclehome模块,打开对应的build.gradle文件

  • dependencies下添加如下代码

    annotationProcessor 'com.alibaba:arouter-compiler:1.5.2'
  • defaultConfig下添加如下代码

    javaCompileOptions {
      annotationProcessorOptions {
          arguments = [AROUTER_MODULE_NAME: project.getName()]
      }
    }

到这里,其实路由的引用配置已经完成,但我们还没有添加Application,也很简单了,在app模块下,新建AppApplication继承自BaseApplication,并将其添加到该模块下的清单文件中。

public class AppApplication extends BaseApplication {

}

这里不做实现是因为演示demo,用不到第三方的东西,实际开发中根据需求进行初始化即可。之所以继承,是因为前面我们已经初始化了路由配置。

测试 ARouter 跳转

配置工作我们已经做完了,本文的主要目的就是测试页面跳转,当然跳转就会包含是否携带参数、跳转是否需要有返回值、以及没有依赖关系的模块间是否可跳转,下面进行分组测试:

tips:为了避免写findViewById() ,我这里使用了ViewBinding,用法很简单,一看就懂,这里不做详细说明。

模块内使用路由跳转

模块内的话,完全可以使用intent方式跳转,但本文的主题是探究路由的跳转用法,我这里以app模块内跳转为例,新建了一个名为MyInfoActivity的页面,显示默认值,通过在MainActivity携带参数跳转赋值来展示使用示例。

跳转传参

如果你的配置都没有错,还是无法跳转,那么卸载APP重新运行,就是Ok的,因为路由地址path有映射,缓存下来了,虽然后面改了,但走的还是缓存。

传参说明

ARouter提供了多种方式传递参数,也支持原生的参数值类型,如下图:

ARouter传参方法

这里不演示全部方法的使用,只要会了下面几个常用的,其他都类似。

  • with(Bundle bundle):如果要传递多个参数,推荐使用该方法。
  • withBundle(String key, Bundle bundle):依然是传递一个Bundle,但可以自定义key .
  • with封装数据类型(String key, 基本数据类型值):如果只传递一个参数,且是基本数据类型,那么这些方法非常实用。

其他常使用的像传递序列化对象、集合等,大家自行尝试。下面说下如何取参数。如下代码是我们的MyInfoActivity的传参:

ARouter.getInstance().build(ARouterPath.APP_MY_INFO)
          .withInt(KEY_TYPE, 100)
          .withString(KEY_NAME, "codexiaosheng")
          .withString(KEY_WEIXIN, "xiaoshengcode")
          .navigation();

补充:可能有细心的朋友注意到,那带返回值方式的跳转如何写呢?

navigation

  • 第三个方法就等同于我们原生写法startActivityForResult()
  • 第四个方法还提供了监听,后面要分享的拦截功能就会使用到。

取参说明

对应上面三个传参方法:

  • with(Bundle bundle):取参数通过getIntent().getExtras()获得Bundle,然后就和我们原生用法相同。
  • withBundle(String key, Bundle bundle)with封装数据类型(String key, 基本数据类型值):取参数方式相同,可以先看一下上面给出的MyInfoActivity的代码:
@Route(path = ARouterPath.APP_MY_INFO)
public class MyInfoActivity extends AppCompatActivity {

    private ActivityMyInfoBinding myInfoBinding;

    @Autowired
    public int u_type;
    @Autowired(name = MainActivity.KEY_NAME)
    public String uName;
    @Autowired(name = MainActivity.KEY_WEIXIN)
    public String uWeixin;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myInfoBinding = ActivityMyInfoBinding.inflate(getLayoutInflater());
        setContentView(myInfoBinding.getRoot());

        ARouter.getInstance().inject(this);

        myInfoBinding.tvName.setText("name:" + uName + " 用户类型:" + u_type);
        myInfoBinding.tvWeixin.setText("weixin:" + uWeixin);
    }

}

可以看到这里和我们平时取参数有几点不同:

  1. 使用了@Autowired注解
  2. 多了ARouter.getInstance().inject(this);这行代码
  3. 接收参数的字段都是public修饰符
  4. 并没有显式的getXXX取值代码

@Autowired注解的说明:<br/>

  • 所注解的变量必须是public
  • 如果变量的名字和传参的key不相同,那么需要手动给注解添加name值,即传参的key.

with(Bundle bundle)这种方式传参方式,其他方式要在接收参数的页面添加下面这行代码:

ARouter.getInstance().inject(this);

如果使用的with(Bundle bundle)传参方式,那么取参数通过getIntent().getExtras()获得Bundle,操作即可。

综合看起来,还是比较简单的,少了很多判断代码。

模块间相互跳转

这里我使用with(Bundle bundle)方式传递参数做演示。先来看一个总体的效果:

效果

这种方式传递参数,在接收的页面上既不用添加@Autowired注解,也不用添加ARouter.getInstance().inject(this);这行代码,使用我们原来的方式getIntent().getExtras()即可。

上面的演示效果中涉及app模块跳转homecircle模块、home模块和circle模块相互跳转,还记得前面的依赖关系吗?homecircle直接是没有依赖关系的,但可以通过路由直接跳转,如果我们项目的module比较多,这就会很方便,降低代码耦合性。

看一下跳转home模块的代码:

// 跳转home模块页面
mainBinding.jumpHomePage.setOnClickListener(v -> {
    if (mainBinding.cbHome.isChecked()) {
        Bundle bundle = new Bundle();
        bundle.putInt(KEY_TYPE, 500);
        bundle.putString(KEY_NAME, "home module");
        bundle.putString(KEY_WEIXIN, "is home module~");

        ARouter.getInstance().build(ARouterPath.HOME_HOME).with(bundle).navigation();
    } else {
        ARouter.getInstance().build(ARouterPath.HOME_HOME).navigation();
    }
});

核心代码都贴出来了,到这基本的演示功能就完成了,本文是以java来演示的,kotlin配置参考官网。

关于路由的高级使用,比如:拦截以及模块可单独运行,下一篇博客会揭晓。

ARouter 通过注解自动注册并且在编译期间生成映射关系,在运行的时候就可以加载文件,通过 path 就可以顺利跳转到目标页面。

  1. 看不到对应的R.layout.xxx_layout文件名了,可以通过点击XXXBinding.getRoot()跳转至对应xml
  2. 如果项目各模块间跳转比较多,建议统一使用路由跳转
  3. ARouter还可以跳转fragment,具体使用查看官方demo
  4. 常见的跳转动画设置,ARouter跳转也是可以的,传入动画资源文件id即可

本文全部代码获取:关注微信公众号code小生回复arouter


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK