module解耦(二)基于路由的解耦

2023-03-10  本文已影响0人  长点点

一、 引言

在安卓开发中,随着项目的复杂度增加,模块化(或组件化)开发方式越来越受到开发者的青睐。模块化开发可以将一个大型项目拆分成多个相对独立的模块,每个模块负责一个功能或业务场景,从而提高代码的可读性、可维护性和可复用性。但是模块化开发也带来了一些挑战,其中之一就是如何实现模块间的解耦和通信。

传统的方式是通过Intent进行页面跳转和数据传递,但这种方式存在以下缺点:

为了解决这些问题,许多开源框架提出了基于路由(Router)的方案。路由是一种将URL映射到具体页面或服务的机制,可以用于将Intent页面跳转的强依赖关系解耦,同时减少跨团队开发的互相依赖问题。

二、 基本概念

2.1 路由

路由(Router)是一种将URL映射到具体页面或服务的机制。URL是一种统一资源定位符(Uniform Resource Locator),用于标识一个资源或目标。URL通常包含以下几个部分:

例如:

https://www.jianshu.com/u/1d9c468843cf/code?userId=aschnloih8ajkbkjb

这个URL包含以下部分:

router://moduleA/pageA?name=Tom&age=18
这个URL表示跳转到moduleA模块中的pageA页面,并传递name和age两个参数。

2.2 路由表

路由表(Router Table)是一种存储URL和页面或服务之间映射关系的数据结构。路由表可以是静态的或动态的,也可以是本地的或远程的。静态路由表是在编译期生成的,动态路由表是在运行期生成的。本地路由表是存储在客户端内存或文件中的,远程路由表是存储在服务器端数据库或配置文件中的。

路由表通常包含以下几个字段:

URL 类名 类型 拦截器 优先级 其他属性
router://moduleA/pageA com.example.modulea.PageAActivity Activity true 1 process=“:moduleA”
router://moduleB/pageB/:id com.example.moduleb.PageBFragment Fragment false 0

这个路由表包含两条记录,分别表示moduleA模块中的pageA页面和moduleB模块中的pageB页面。其中pageB页面支持路径参数id,用于传递动态数据。

2.3 路由器

路由器(Router)是一种负责处理URL请求和跳转到相应页面或服务的组件。路由器通常包含以下几个功能:

// 初始化
Router.init(context);

// 解析
Postcard postcard = Router.parse("router://moduleA/pageA?name=Tom&age=18");

// 拦截
boolean intercepted = Router.intercept(postcard);

// 跳转
Router.navigate(postcard);

// 回调
Router.setCallback(new Callback() {
    @Override
    public void onSuccess(Postcard postcard) {
        // 跳转成功
    }

    @Override
    public void onFail(Postcard postcard) {
        // 跳转失败
    }
});

这段代码演示了使用Router组件进行URL请求处理和跳转到pageA页面的过程。

2.4 拦截器

拦截器(Interceptor)是一种负责对URL请求进行拦截和处理的组件。拦截器通常用于实现以下功能:

public class LoginInterceptor implements Interceptor {
    @Override
    public boolean intercept(Postcard postcard) {
        // 判断当前用户是否已经登录
        if (!UserManager.isLogin()) {
            // 跳转到登录页面
            Router.navigate("router://moduleA/login");
            return true;
        }
        return false;
    }
}

这个拦截器实现了登录检查的功能,如果当前用户没有登录,则跳转到登录页面,并拦截原始请求。

三、使用实例

本节将以一个简单的示例来演示如何使用基于路由的module解耦方案。假设我们有一个电商项目,包含以下几个模块:

为了实现这些模块之间的解耦和通信,我们可以使用一个开源框架ARouter来实现基于路由的方案。ARouter是一个轻量级且功能强大的路由框架,支持静态路由表生成、自动参数注入、多种类型跳转、多种拦截器配置等功能。

3.1 配置依赖

首先,在项目根目录下的build.gradle文件中添加ARouter插件依赖:

buildscript {
    dependencies {
        classpath "com.alibaba:arouter-register:1.0.2"
    }
}

然后,在每个子模块下的build.gradle文件中添加ARouter库依赖,并应用ARouter插件:

apply plugin: 'com.alibaba.arouter'

dependencies {
    implementation "com.alibaba:arouter-api:1.5.2"
    annotationProcessor "com.alibaba:arouter-compiler:1.5.2"
}

最后,在app模块下的build.gradle文件中添加以下配置:

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

这样就完成了ARouter框架在项目中的配置。

3.2 初始化路由器

接下来,在app模块中创建一个Application类,并在onCreate方法中初始化路由器:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化路由器
        ARouter.init(this);
    }
}

同时,在AndroidManifest.xml文件中注册该Application类,并添加meta-data标签指定路由表生成路径:

<application
    android:name=".MyApplication">
    
    <meta-data
        android:name="ROUTER_MODULE_APP"
        android:value="app/src/main/java/com/example/app/router" /> </application>

这样就完成了路由器在app模块中的初始化。

3.3 注册页面和服务

然后,在每个子模块中,使用@Route注解来注册页面和服务,并指定对应的URL和其他属性:

// home模块中的HomePageActivity
@Route(path = "router://home/homePage")
public class HomePageActivity extends AppCompatActivity {
    // ...
}

// detail模块中的DetailPageActivity
@Route(path = "router://detail/detailPage", extras = 1)
public class DetailPageActivity extends AppCompatActivity {
    // ...
}

// cart模块中的CartService实现类
@Route(path = "router://cart/cartService")
public class CartServiceImpl implements CartService {
    // ...
}

// user模块中的UserService实现类
@Route(path = "router://user/userService")
public class UserServiceImpl implements UserService {
    // ...
}

这样就完成了页面和服务在各个子模块中的注册。

3.4 跳转页面和调用服务

接下来,在任意一个子模块中,可以使用ARouter.getInstance()方法获取路由器实例,并通过build方法构建Postcard对象,然后通过navigation方法进行跳转或调用:

// 从home模块跳转到detail模块的DetailPageActivity,并传递商品id参数
ARouter.getInstance().build("router://detail/detailPage").withString("id", "123456").navigation();

// 从detail模块调用cart模块的CartService接口,添加商品到购物车
CartService cartService = ARouter.getInstance().build("router://cart/cartService").navigation();
cartService.addProductToCart(product);

// 从cart模块调用user模块的UserService接口,获取用户信息
UserService userService = ARouter.getInstance().build("router://user/userService").navigation();
User user = userService.getUserInfo();

这样就完成了页面和服务在各个子模块之间的跳转和调用。

3.5 配置拦截器

最后,在任意一个子模块中,可以使用@Interceptor注解来配置拦截器,并指定优先级和名称:

// 配置一个登录拦截器,优先级为8,名称为loginInterceptor
@Interceptor(priority = 8, name = "loginInterceptor")
public class LoginInterceptor implements IInterceptor {

    @Override
    public void process(Postcard postcard) {
        // 判断当前请求是否需要登录检查(extras为1表示需要)
        if (postcard.getExtras() == 1) {
            // 判断当前用户是否已经登录
            if (!UserManager.isLogin()) {
                // 跳转到登录页面,并传递原始请求信息(requestCode为100表示是从拦截器跳转过来)
                ARouter.getInstance().build("router://user/login").with(postcard).withInt("requestCode", 100).navigation();
                // 拦截当前请求,并设置结果码为失败(RESULT_FAILED表示失败)
                postcard.setGreenChannel();
                postcard.withInt("resultCode", RESULT_FAILED);
            }
        }
        // 继续执行下一个拦截器或目标请求(onContinue方法表示继续)
        callback.onContinue(postcard);
    }

    @Override
    public void init(Context context) {
        // 初始化拦截器相关资源(可选)
    }
}

这样就完成了拦截器在某个子模块中的配置。

四、优缺点分析

1.基于路由的module解耦方案有以下优点:

2.基于路由的module解耦方案也有以下缺点:

上一篇 下一篇

猜你喜欢

热点阅读