Paste_Image.png
上图是目前比较普遍使用的Android APP技术架构,往往是在一个界面中存在大量的业务逻辑,而业务逻辑中充斥着各种网络请求、数据操作等行为,整个项目中也没有模块的概念,只有简单的以业务逻辑划分的文件夹,并且业务之间也是直接相互调用、高度耦合在一起的;
Paste_Image.png
上图单一工程模型下的业务关系,总的来说就是:你中有我,我中有你,相互依赖,无法分离。
然而随着产品的迭代,业务越来越复杂,随之带来的是项目结构复杂度的极度增加,此时我们会面临如下几个问题:
1、实际业务变化非常快,但是单一工程的业务模块耦合度太高,牵一发而动全身;
2、对工程所做的任何修改都必须要编译整个工程;
3、功能测试和系统测试每次都要进行;
4、团队协同开发存在较多的冲突.不得不花费更多的时间去沟通和协调,并且在开发过程中,任何一位成员没办法专注于自己的功能点,影响开发效率;
5、不能灵活的对业务模块进行配置和组装;
Paste_Image.png
上图是组件化工程模型
Paste_Image.png
上图是组件化开发在Android studio里面的目录工程结构
Paste_Image.png
这是组件化工程模型下的业务关系,业务之间将不再直接引用和依赖,而是通过“路由”这样一个中转站间接产生联系,我们今天要讲的就是这个路由。
路由怎么工作呢?
比如上面图中,每个业务分别在不同的moudle中,分别有ActivityA、ActivityB、ActivityC、ActivityD。
假如ActivityA想跳转到ActivityB怎么实现呢?通常跳转是这么写的:
Intent intent = new Intent(this,ActivityB.class);
startActivity(intent);
但是现在业务A和业务B在不同的moudle中,A业务中没法 import ActivityB,因为A和B是相互独立,没有依赖的。
路由做的事情就是在不用引导类的情况下实现这一跳转。
现在比较流行的路由有两个ActivityRouter、ARouter
ActivityRouter是个人项目
ARouter是阿里的项目
我们选择阿里的Arouter好一点
先看下ARouter的使用方法
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
}
}
dependencies {
// 替换成最新版本, 需要注意的是api
// 要与compiler匹配使用,均使用最新版可以保证兼容
compile 'com.alibaba:arouter-api:x.x.x'
annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
...
}
然后在Application中初始化
if (isDebug()) { // 这两行必须写在init之前,否则这些配置在init过程中将无效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
}
ARouter.init(mApplication); // 尽可能早,推荐在Application中初始化
接着使用注解标记要跳转的Activity
@Route(path = "/module_b/activity_b")
public class ActivityB extend Activity {
...
}
然后在ActivityA中这样跳转到ActivityB
ARouter.getInstance().build("/module_b/activity_b").navigation();
这样就完成了不同业务之间的跳转,是不是超级简单?
当然跳转一般都会传参数
// 2. 跳转并携带参数
ARouter.getInstance().build("/module_b/activity_b")
.withLong("key1", 666L)
.withString("key3", "888")
.withObject("key4", new Test("Jack", "Rose"))
.navigation();
在ActivityB中获取参数有两种方式,一种是普通Activity那样getIntent().getXXX
加一种是使用@Autowired注解的方式
@Route(path = "/test/activity")
public class Test1Activity extends Activity {
@Autowired
public String name;
@Autowired
int age;
@Autowired(name = "girl") // 通过name来映射URL中的不同参数
boolean boy;
@Autowired
TestObj obj; // 支持解析自定义对象,URL中使用json传递
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ARouter.getInstance().inject(this);
// ARouter会自动对字段进行赋值,无需主动获取
Log.d("param", name + age + boy);
}
}
还有一种情况,业务A是要使用业务C中的某个服务或者说某种功能,并不是想跳转Activity
这种情况下就要使用到IProvider
// 声明接口,其他组件通过接口来调用服务
public interface HelloService extends IProvider {
String sayHello(String name);
}
// 实现接口
@Route(path = "/service/hello", name = "测试服务")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "hello, " + name;
}
@Override
public void init(Context context) {
}
}
申明的接口放在base module中,接口的实现放在具体功能实现的module中。
然后在要使用这一服务的module中这样使用:
HelloService helloService = (HelloService) ARouter.getInstance().build("/service/hello").navigation();
helloService.sayHello("Vergil");
这样就实现了调用其他业务服务
还有还可能通过ARouter获取其他业务模块的Fragment:
// 获取Fragment
Fragment fragment = (Fragment) ARouter.getInstance().build("/test/fragment").navigation();
下面是一些特殊用法:
// 构建标准的路由请求,startActivityForResult
// navigation的第一个参数必须是Activity,第二个参数则是RequestCode
ARouter.getInstance().build("/home/main", "ap").navigation(this, 5);
上面是从Activity调startActivityForResult 但是Arouter没有API支持从fragment调startActivityForResult
这种情况要怎么办呢?
可以这样做
Postcard postcard = ARouter.getInstance().build("/module2/activity");
LogisticsCenter.completion(postcard);
Class<?> destination = postcard.getDestination();
这里得到的destination类就是我们要跳转的类,这样fragment的startActivityForResult就好办了
Intent intent = new Intent(getContext(),destination);
startActivityForResult(intent,requestCode);