前言:

前面分析了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. 用php做注册审核

    做注册审核就像前面讲的注册登录一样,也是要连接数据库 首先在数据库内要做这样一张表: 表名为users表 里面的列名分别为用户名,密码,姓名,性别,生日,账户的状态,照片 然后就可以写代码了,要注册的 ...

  2. 一起学微软Power BI系列-使用技巧(4)Power BI中国版企业环境搭建和帐号问题

    千呼万唤的Power BI中国版终于落地了,相信12月初的微软技术大会之后已经铺天盖地的新闻出现了,不错,Power BI中国版真的来了,但还有些遗憾,国际版的一些重量级服务如power bi emb ...

  3. 对抗假人 —— 前后端结合的 WAF

    前言 之前介绍了一些前后端结合的中间人攻击方案.由于 Web 程序的特殊性,前端脚本的参与能大幅弥补后端的不足,从而达到传统难以实现的效果. 攻防本为一体,既然能用于攻击,类似的思路同样也可用于防御. ...

  4. ASP.NET Core 中间件之压缩、缓存

    前言 今天给大家介绍一下在 ASP.NET Core 日常开发中用的比较多的两个中间件,它们都是出自于微软的 ASP.NET 团队,他们分别是 Microsoft.AspNetCore.Respons ...

  5. ASP.NET Core应用针对静态文件请求的处理[4]: DirectoryBrowserMiddleware中间件如何呈现目录结构

    和StaticFileMiddleware中间件一样,DirectoryBrowserMiddleware中间本质上还是定义了一个请求地址与某个物理目录之间的映射关系,而目标目录体现为一个FilePr ...

  6. TYPESDK手游聚合SDK服务端设计思路与架构之一:应用场景分析

    TYPESDK 服务端设计思路与架构之一:应用场景分析 作为一个渠道SDK统一接入框架,TYPESDK从一开始,所面对的需求场景就是多款游戏,通过一个统一的SDK服务端,能够同时接入几十个甚至几百个各 ...

  7. JavaScript事件代理和委托(Delegation)

    JavaScript事件代理 首先介绍一下JavaScript的事件代理.事件代理在JS世界中一个非常有用也很有趣的功能.当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委 ...

  8. SMBus set up a 2-byte EEPROM address for read/write

    Sequencer Engine spec: http://www.analog.com/media/en/technical-documentation/data-sheets/ADM1260.pd ...

  9. Oracle 表空间和用户权限管理

    一. 表空间 Oracle数据库包含逻辑结构和物理结构. 数据库的物理结构指的是构成数据库的一组操作系统文件. 数据库的逻辑结构是指描述数据组织方式的一组逻辑概念以及它们之间的关系. 表空间是数据库逻 ...

  10. Windows下Redis缓存服务器的使用 .NET StackExchange.Redis Redis Desktop Manager

    Redis缓存服务器是一款key/value数据库,读110000次/s,写81000次/s,因为是内存操作所以速度飞快,常见用法是存用户token.短信验证码等 官网显示Redis本身并没有Wind ...