前言:

前面分析了APP的现状以及业务组件化的一些探讨(Android业务组件化之现状分析与探讨),以及通信的桥梁Scheme的使用(Android业务组件化之URL Scheme使用),今天重点来聊下子模块SubModule的拆分以及它们之间的路由Router实现。本篇涉及的相关知识比较多,阅读本篇之间需要大致了解一下Java的注解(Java学习之注解Annotation实现原理)、Java的动态代理机制(Java设计模式之代理模式(Proxy))等。业务组件化是一个循序渐进的过程,一开始很难就能拿出终极解决方案,还是一步步来走的比较踏实实在。

业务组件化相关文章地址:

我们首先搞清楚什么是业务组件?

搞清楚这个对我们来说至关重要,否则很难拆分业务与依赖库,也很难搞清楚哪些类应该放在业务子模块里面哪些类应该放在依赖库里面。

1.)和业务无关

完全和业务没有一点关系,比如项目中常用的各种Utils工具类,一些公共自定义控件例如显示圆角图片的ImageView等

2.)弱业务

为什么称之为弱业务,原因就是这些不是完整的业务,但是又和APP业务相关,比如我们的网络请求,数据库操作等。

3.)业务

这个就是我们针对要拆分的业务组件,一个完整的独立的业务线才能称之为业务,比如我们APP的登录注册业务等。

业务组件的拆分粒度?

业务组件的拆分将是整个整改的重点,关于拆分的粒度也将成为讨论的焦点,到底是粗一点好还是细一点好?粗一点更容易拆分,细一点更容易解耦灵活度高,这个根据实际情况来定,由于我们项目整改的过程中不能影响到新需求的开发,开始还是以粗一点的粒度进行拆分,先把大致几个业务拆分出来,后期慢慢再做细。

子模块SubModule拆分:

1.)子模块没有拆分之间

页面跳转

Intent intent = new Intent(this, XXX.class);
startActivity(intent);

数据传递

直接页面startActivityForResult返回获取, 间接页面通过存储或者变量 ,或者借助开源框架EventBus等传递

没有拆分的这种开发方式,其实使用起来简单方便,但是这种显示调用没有任务文档,每一个跳转页面都要和相关开发人员沟通,沟通成本比较高。

2.)拆分子模块之后

拆分子模块之后,任何模块之间的跳转都要采用路由Router中转,需要在相关Activity中配置如下信息

        <activity
android:name=".GoodsDetailActivity"
android:theme="@style/AppTheme">
<intent-filter>
<data
android:host="goods"
android:path="/goodsDetail"
android:port="8888"
android:scheme="xl"/>
<category android:name="android.intent.category.DEFAULT"/> <action android:name="android.intent.action.VIEW"/> <category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>

页面跳转

    /**
* 通过uri跳转指定页面
*
* @param url
*/
private void openRouterUri(String url) {
PackageManager packageManager = mContext.getPackageManager();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isValid = !activities.isEmpty();
if (isValid) {
mContext.startActivity(intent);
}
}

数据的传递同样可以直接页面startActivityForResult返回获取, 间接页面通过存储或者变量 ,或者借助开源框架EventBus等传递,但是这些弱业务公共数据统一放在依赖库里。模块之间不存在代码引用。通过这种方式android,iOS与H5客户端可以通过一些简单的url来实现跳转了,通维护一份文档来约束各个页面的参数。

3.)路由Router简单实现

1.定义两个注解参数,一个标示URI注解,一个标示参数

RouterUri.java
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface RouterUri { String routerUri() default ""; }
RouterParam.java
@Documented
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface RouterParam { String value() default ""; }

 2.定义一个URI协议接口

IRouterUri.java
public interface IRouterUri {

    @RouterUri(routerUri = "xl://goods:8888/goodsDetail")//请求Url地址
void jumpToGoodsDetail(@RouterParam("goodsId") String goodsId, @RouterParam("des") String des);//参数商品Id 商品描述 }

3.定义一个单例,内部通过动态代理机制实现跳转

public class XLRouter {
private final static String TAG = XLRouter.class.getSimpleName();
private static IRouterUri mRouterUri;
private static Context mContext; /**
* 初始化
*/
public static void initXLRouter(Context context) {
mContext = context.getApplicationContext();
mRouterUri = create(IRouterUri.class);
} /**
* 返回Api
*/
public static IRouterUri routerUri() {
return mRouterUri;
} private static IRouterUri create(Class<?> aClass) {
return (IRouterUri) Proxy.newProxyInstance(aClass.getClassLoader(), new Class<?>[]{aClass},
new InvocationHandler() { @Override
public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
StringBuilder stringBuilder = new StringBuilder();
RouterUri reqUrl = method.getAnnotation(RouterUri.class);
Log.e(TAG, "IReqApi---reqUrl->" + reqUrl.routerUri());
stringBuilder.append(reqUrl.routerUri());
//Type[] parameterTypes = method.getGenericParameterTypes();//获取注解参数类型
Annotation[][] parameterAnnotationsArray = method.getParameterAnnotations();//拿到参数注解
//Annotation[] annotation = method.getDeclaredAnnotations();
int pos = 0;
for (int i = 0; i < parameterAnnotationsArray.length; i++) {
Annotation[] annotations = parameterAnnotationsArray[i];
if (annotations != null && annotations.length != 0) {
if (pos == 0) {
stringBuilder.append("?");
} else {
stringBuilder.append("&");
}
pos++;
RouterParam reqParam = (RouterParam) annotations[0];
stringBuilder.append(reqParam.value());
stringBuilder.append("=");
stringBuilder.append(args[i]);
Log.e(TAG, "reqParam---reqParam->" + reqParam.value() + "=" + args[i]);
}
}
//下面就可以执行相应的跳转操作
openRouterUri(stringBuilder.toString());
return null;
}
});
} /**
* 通过uri跳转指定页面
*
* @param url
*/
private static void openRouterUri(String url) {
PackageManager packageManager = mContext.getPackageManager();
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isValid = !activities.isEmpty();
if (isValid) {
mContext.startActivity(intent);
}
}
}

4.)在进行XLRouter初始化

XLRouter.initXLRouter(this);

5.调用方式

XLRouter.routerUri().jumpToGoodsDetail("1000110002","goods des");

总结:

要实现真正的业务组件化任重而道远,我们这里实现第一步拆分子模块,让各个模块的代码各自维护,先解耦他们之间的依赖关系,在app壳工程通过compile project(':umeng_social_sdk_library')这种方式选择性接入哪个子模块,开发过程中开发哪个模块就引入哪个模块,测试环节也是如此,测试哪个模块打包引入哪个模块,最终测试需要引入全部相关模块,测试上线。

Android业务组件化之子模块SubModule的拆分以及它们之间的路由Router实现的更多相关文章

  1. Android业务组件化之现状分析与探讨

    前言: 从个人经历来说的话,从事APP开发这么多年来,所接触的APP的体积变得越来越大,业务的也变得越来越复杂,总来来说只有一句话:这是一个APP臃肿的时代!所以为了告别APP臃肿的时代,让我们进入一 ...

  2. Android业务组件化之URL Scheme使用

    前言: 最近公司业务发展迅速,单一的项目工程不再适合公司发展需要,所以开始推进公司APP业务组件化,很荣幸自己能够牵头做这件事,经过研究实现组件化的通信方案通过URL Scheme,所以想着现在还是在 ...

  3. Android业务组件化之Gradle和Sonatype Nexus搭建私有maven仓库

    前言: 公司的业务组件化推进的已经差不多三四个月的时间了,各个业务组件之间的解耦工作已经基本完成,各个业务组件以module的形式存在项目中,然后项目依赖本地的module,多少有点不太利于项目的并行 ...

  4. 【转】Android业务组件化之URL Scheme使用

    前言: 最近公司业务发展迅速,单一的项目工程不再适合公司发展需要,所以开始推进公司APP业务组件化,很荣幸自己能够牵头做这件事,经过研究实现组件化的通信方案通过URL Scheme,所以想着现在还是在 ...

  5. Android 业务组件化开发实践

    组件化并不是新话题,其实很早很早以前我们开始为项目解耦的时候就讨论过的.但那时候我们说的是功能组件化.比如很多公司都常见的,网络请求模块.登录注册模块单独拿出来,交给一个团队开发,而在用的时候只需要接 ...

  6. Android项目架构之业务组件化

    前言: 从个人经历来说的话,从事APP开发这么多年来,所接触的APP的体积变得越来越大,业务的也变得越来越复杂,总来来说只有一句话:这是一个APP臃肿的时代!所以为了告别APP臃肿的时代,让我们进入一 ...

  7. Android的组件化和模块化

    Android随着业务的增多,而且后续新的需求的增加,代码的修改会变得非常频繁 然后最近在看组件化和模块化 公司的业务没有那么大,所以这种方式我并没有采取 但是还是需要了解下他的使用机制 还有优缺点之 ...

  8. Android彻底组件化demo发布

    今年6月份开始,我开始负责对"得到app"的android代码进行组件化拆分,在动手之前我查阅了很多组件化或者模块化的文章,虽然有一些收获,但是很少有文章能够给出一个整体且有效的方 ...

  9. [Android Pro] 组件化:企业级大型项目必经之路

    cp : https://www.csdn.net/article/2011-02-11/291667 摘要:超过一年以上.活跃开发的项目往往到后期陷入了一些共性的问题: 构建速度慢,往往生成一次最终 ...

随机推荐

  1. Asp.Net Mvc 使用WebUploader 多图片上传

    来博客园有一个月了,哈哈.在这里学到了很多东西.今天也来试着分享一下学到的东西.希望能和大家做朋友共同进步. 最近由于项目需要上传多张图片,对于我这只菜鸟来说,以前上传图片都是直接拖得控件啊,而且还是 ...

  2. java中的字符串相关知识整理

    字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...

  3. 在Openfire上弄一个简单的推送系统

    推送系统 说是推送系统有点大,其实就是一个消息广播功能吧.作用其实也就是由服务端接收到消息然后推送到订阅的客户端. 思路 对于推送最关键的是服务端向客户端发送数据,客户端向服务端订阅自己想要的消息.这 ...

  4. 在Ubuntu下搭建ASP.NET 5开发环境

    在Ubuntu下搭建ASP.NET 5开发环境 0x00 写在前面的废话 年底这段时间实在太忙了,各种事情都凑在这个时候,没时间去学习自己感兴趣的东西,所以博客也好就没写了.最近工作上有个小功能要做成 ...

  5. 猫哥网络编程系列:HTTP PEM 万能调试法

    注:本文内容较长且细节较多,建议先收藏再阅读,原文将在 Github 上维护与更新. 在 HTTP 接口开发与调试过程中,我们经常遇到以下类似的问题: 为什么本地环境接口可以调用成功,但放到手机上就跑 ...

  6. react-redux

    1. 首先redux,与react是两个独立的个体,项目中可以只用react,也可以只用redux 1.1 react-redux: 是一个redux作者专门为react制作的 redux, 增加了新 ...

  7. 【原】AFNetworking源码阅读(一)

    [原]AFNetworking源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 AFNetworking版本:3.0.4 由于我平常并没有经常使用AFNetw ...

  8. CoreCRM 开发实录——Travis-CI 实现 .NET Core 程度在 macOS 上的构建和测试 [无水干货]

    上一篇文章我提到:为了使用"国货",我把 Linux 上的构建和测试委托给了 DaoCloud,而 Travis-CI 不能放着不用啊.还好,这货支持 macOS 系统.所以就把 ...

  9. ASP.NET Core project.json imports 是什么意思?

    示例代码: "frameworks": { "netcoreapp1.0.0": { "imports" : "portable- ...

  10. 通过VMware的PowerCLI配置集群内指定主机的vMotion功能

    PowerCLI是VMware开发的基于微软(MSFT)的PowerShell的命令行管理vSphere的实现,因此在批量化操作方面CLI会减轻很多GUI环境下的繁琐重复劳作. 现有场景中有大量的物理 ...