使用ARouter实现组件化
使用ARouter实现组件化
ARouter是阿里在github上面的一个开源项目,地址是:ARouter 本文不是重点分享ARouter的使用,而是分享使用ARouter如何去组件化。关于它的详细使用,大家可以看文档以及加群向询问。关于如何编写一个路由实现组件化,推荐看我同事的一篇文章手把手教你写Router框架入门篇
组件化的优点
- 解耦,使得各自业务模块专注于自己的业务实现,而可以不关系别的模块业务。
- 方便开发,在多人开发的时候,可以各自开发自己的特定模块,除了底层模块之外
- 可配置,复用性强,针对不同的App,可以有不同的模块而不必做出大的改变。
- 每个模块可以独立运行,方便开发调试。
- 大家补充
组件化开发的实现
项目结构是:
配置
- 大家按照ARouter的文档去配置一些东西,需要注意的是每一个模块都必须引入compile sdk,处理API SDk可以在Base sdk里面引入就行。
- Annotation sdk不用我们引入,他会自己自动依赖引入
- 在开发的时候,每一个module 的分组都必须不同,或者将会有一个 类重复的错误。分组就是path的第一个"/"与第二个"/"之间。
思路
我们是需要拆分组件,不同的模块负责自己的业务实现,不和其他模块有依赖关系的存在。假如这个模块需要启动别的Activity或者是调用别的模块方法,我们就通过ARouter提供的方法去实现。模块图如下:
模块解析与划分规则:
- App模块 App模块就是我们的Apk模块,他是我们的最终产物。他可以按照需要配置自己需要的模块,进行一些初始化的工作。
- module模块 Module模块就是我们的业务实现模块,他是只负责本module的业务而不负责其他的业务,他是通过使用ARouter提供的方法和接口,实现调用外部数据和提供方法给外部调用,也就是图里面的Provider。
- base模块 关于base模块,大家也可以继续拆分一些细的模块,比如把router独立处理,但是不建议拆分太多,因为base模块是会变动较大,就是在版本的迭代过程中,不断变化的,被拆分较多的话开发起来不是很方便。因为有依赖的传递的关系,比如base 依赖于本project的较多模块,当设计到底层较多模块修改,那么就需要一层一层的在传递上去。 base模块应该是与业务无关的模块,在本例子中,base模块负责管理Router,同时提供一些基础的东西,比如BaseActivit,Util资源等。假如我们有自家的sdk,网络库依赖等,建议是在base中引入。
实践
管理Router
我们使用一个ModuleManager,提供一个Map,Map是使用对应module的Provider的path作为key和value。以及相关的数据结构,用来对ARouter的进行二次封装和管理模块。 大概实现如下:
public class ModuleManager {private ModuleOptions options;private ModuleManager() {}private static class ModuleManagerHolder {private static final ModuleManager instance = new ModuleManager();}public static ModuleManager getInstance() {return ModuleManagerHolder.instance;}public void init(ModuleOptions options) {if (this.options == null && options != null) {this.options = options;}}public ModuleOptions getOptions() {return options;}public boolean hasModule(String key) {return options.hasModule(key);}
}
复制代码
ModuleOptions就是具体管理那些包含那些模块的配置。该类是在App或者是测试module独立运行(后面提到)的时候进行初始化。例如:
public class CustomApplication extends BaseApplication {@Overridepublic void onCreate() {super.onCreate();initARouter();}private void initARouter() {if (LG.isDebug) {ARouter.openLog();ARouter.openDebug();ARouter.printStackTrace();}ARouter.init(this);ModuleOptions.ModuleBuilder builder = new ModuleOptions.ModuleBuilder(this).addModule(IHomeProvider.HOME_MAIN_SERVICE, IHomeProvider.HOME_MAIN_SERVICE).addModule(IModule1Provider.MODULE1_MAIN_SERVICE, IModule1Provider.MODULE1_MAIN_SERVICE).addModule(IModule2Provider.MODULE2_MAIN_SERVICE, IModule2Provider.MODULE2_MAIN_SERVICE).addModule(IModule4Provider.MODULE4_MAIN_SERVICE, IModule4Provider.MODULE4_MAIN_SERVICE).addModule(IModule5Provider.MODULE5_MAIN_SERVICE, IModule5Provider.MODULE5_MAIN_SERVICE);ModuleManager.getInstance().init(builder.build());}
}
复制代码
这样子就完成了对改App或者是module的管理。
管理服务
我们使用一个ServiceManager,用来获取不同模块的服务,即Provider。安装ARouter的文档,我们通过继承IProvider,编写一个对应模块的接口,提供接口方法,在对应模块实现该Provider。然后该Provider我们就是在ServiceManager里面进行管理和获取。比如: home模块实现一个IHomeProvider,实现类是HomeProvider。
//接口
public interface IHomeProvider extends IBaseProvider {//ServiceString HOME_MAIN_SERVICE = "/home/main/service";//开屏String HOME_ACT_SPLASH = "/home/act/splash";//home主页String HOME_ACT_HOME = "/home/act/home";String HOME_TABTYPE = "home_tab_type";void toast(String msg);void selectedTab(Activity activity,int position);
}
//实现类
@Route(path = IHomeProvider.HOME_MAIN_SERVICE)
public class HomeProvider implements IHomeProvider {private Context context;@Overridepublic void init(Context context) {this.context = context;}@Overridepublic void toast(String msg) {Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();}@Overridepublic void selectedTab(Activity activity,int position) {if (activity instanceof HomeActivity) {((HomeActivity) activity).selectedTab(position);}}
}
复制代码
然后在ServiceManager中,
//也可以使用自动注入,这里是手动发现并且调用public IModule1Provider getModule1Provider() {return module1Provider != null ? module1Provider : (module1Provider = ((IModule1Provider) MyRouter.newInstance(IModule1Provider.MODULE1_MAIN_SERVICE).navigation()));}
复制代码
我们对本Project的所有服务进行管理。然后,在base当中,提供不同的Service,对Provider进行调用,同时提供Intent方法,去启动不同模块的Activity,比如:
//管理调用Provider的某一个特定模块的Service
public class HomeService {private static boolean hasModule() {return ModuleManager.getInstance().hasModule(IHomeProvider.HOME_MAIN_SERVICE);}public static void selectedTab(Activity activity, int position) {if (!hasModule()) return;ServiceManager.getInstance().getHomeProvider().selectedTab(activity, position);}
}
//管理该module的Activity跳转
public class HomeIntent {private static boolean hasModule() {return ModuleManager.getInstance().hasModule(IHomeProvider.HOME_MAIN_SERVICE);}public static void launchHome(int tabType) {//HomeActivityMyBundle bundle = new MyBundle();bundle.put(IHomeProvider.HOME_TABTYPE, tabType);MyRouter.newInstance(IHomeProvider.HOME_ACT_HOME).withBundle(bundle).navigation();}
}
复制代码
Module可独立运行配置
经过这两个,我们就已经基本完成了项目组件化。但是对于组件化,我们还有一个特点,就是每一个module都是可以独立运行的,方便开发和调试。那么,我们应该怎么弄?
- 我们提供两种环境,一个是debug,一种是release,debug的时候,我们是可运行的独立模块,release的时候,我们是library。
- debug的时候,我们需要提供一些测试代码和一套初始化。 例如:我们需要module1是可以独立运行的,在本demo中,他是一个Fragment作为主入口被别的模块添加使用,所以我们的debug中需要添加一个Activity,一套清单,一些资源。 我们使用config.gradle去管理我们的一些外部依赖arr以及我们的一些编译版本号,sdk版本号等,如下:
ext {//...版本号以及arr管理//home是否是作为模块,true的时候是,false的时候可以独立运行,ps名字有点不对,不想改了ORZisMouleDebugHome = true;//module1是否是作为模块,true的时候是,false的时候可以独立运行isModule1Debug = true;
}
复制代码
然后,在跟build.gradle第一行中apply 进去。
apply from: "config.gradle"
复制代码
然后,使用sourceSets对代码进行管理,配置debug和release的代码,module1的结构如下
他的gradle配置如下:
if (rootProject.ext.isModule1Debug) {apply plugin: 'com.android.library'
} else {apply plugin: 'com.android.application'
}
android {compileSdkVersion rootProject.ext.android.compileSdkVersionbuildToolsVersion rootProject.ext.android.buildToolsVersiondefaultConfig {minSdkVersion rootProject.ext.android.minSdkVersiontargetSdkVersion rootProject.ext.android.targetSdkVersionversionCode 101versionName "1.0.1"if (!rootProject.ext.isModule1Debug) {applicationId "com.github.io.liweijie.lib1"}javaCompileOptions {annotationProcessorOptions {arguments = [moduleName: project.getName()]}}}compileOptions {sourceCompatibility JavaVersion.VERSION_1_7targetCompatibility JavaVersion.VERSION_1_7}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}sourceSets {main {if (!rootProject.ext.isModule1Debug) {manifest.srcFile 'src/debug/AndroidManifest.xml'java.srcDir 'src/debug/java/'res.srcDirs=['src/debug/res']} else {manifest.srcFile 'src/release/AndroidManifest.xml'java.srcDir 'src/release/java/'}}}
}
dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {exclude group: 'com.android.support', module: 'support-annotations'})compile project(':base')testCompile 'junit:junit:4.12'annotationProcessor rootProject.ext.dependencies["aroutercompiler"]
}
复制代码
这里需要注意的问题是,debug和relase的清单都需要声明需要的activity以及其他组件。debug中还应该配置Application,进行ARouter的初始化。 经过这样子,我们的每一个module都是可以独立运行的模块了。一般而言,release其实是没有什么东西的,因为release需要的就是我们module本身需要的业务逻辑实现代码,他是作为library去使用的,看自己项目是否需要配置relase。 在本项目中,修改对应的config.gradle中的值就可以使得module1和home独立运行或者是作为lib添加。 最终结果如图:
App独立运行:
App2独立运行:
home独立运行:
module1独立运行:
组件化开发的建议
- 在我们每一个模块文档之后,我们应该使用arr的形式引入依赖,上传我们的maven库,再去compile下来,同时注释掉setting.gradle的配置,这样子有助于编译加快。
- 删除各个module的test代码,也就是src目录下的test,因为那些都是包含一些task的,在同步或者是编译的时候会被执行,减慢了编译速度。
- 四大组件应该在各自module里面声明。
- 在Base中提供一个BaseApplication。
旧项目组件化过程实践
最近在做公司的App,和同事一起把负责的App组件化了,在这个过程中有一些坑跟大家分享一下,避免大家再踩。
- 不要一步彻底的组件化,步子不要迈得太大,建议是先将比较容易的组件进行拆分出来,先做成模块,然后一边进行业务的迭代,两边都不耽误,除非你有足够时间进行组件化工作才去彻底组件化。
- 关于资源的拆分,一些style,一些常见的string,一些共用的图片,drawable等资源,建议存放在base module当中,可以共用。对于属于不同模块的资源,建议不要存放在base,可能一开始你直接把所有的资源都放到base里面会比较好做,比如不用担心编译错误,资源无法寻找到,需要一个一个的复制的问题,但是,你存放到了base,而base模块,一般开发过程中,是经常变动的,那么,就是他会经常被编译,就会带来一个编译的速度问题,所以应该各个模块存放自己的资源。
- 关于Base的依赖库问题,比如我们可能有自家的sdk,第三方的依赖等等,这些,与业务逻辑无关的依赖,建议是使用一个单独的project 进行二次封装,封装完成之后,打包arr 依赖,上传自家maven库,通过compile 进行base,或者是特定模块,不建议直接在app中新建module。比如,我们要引入volley,我们应该使用一个新的project,对volley进行二次封装,稳定之后,通过compile arr 引入base 或者是其他模块中。这样子这些与业务逻辑无关的也方便公司其他项目使用。
- 针对旧项目拆分的module,可以暂时不编写debug,也就是可以不用使得旧项目可以独立运行,因为他涉及的初始化逻辑可能较多,时间不够,直接被app依赖运行测试。针对新的module,可以编写debug来使得新module独立运行,方便调试。
组件化带来的问题
- 由于项目的组价话,可能需要每个业务拆分的比较开,那么将会导致module也比较的多。到了最后,可能是一个模块带一个Activity以及一个Fragment作为一个组件,那么将会比较难的开发,所以,模块的拆分,我们需要按照我们实际项目进行划分模块,不要划分太细致。同时,在旧项目组件化过程中,由于各个模块尚未成熟,还没有稳定,那么就会有比较多的模块进行编译,速度也是比较慢的,所以旧项目的拆分也是需要按照一定的步骤慢慢拆分。同时,建议使用Activity+Fragment的方式进行组件化,方便被别的组件使用,Activity不涉及一般逻辑。
- 有时候修改base库,需要修改依赖方式会比较的麻烦。
- 有时候会有资源冲突问题,这个我们在gradle里面为模块资源添加一个前缀解决
项目GitHub地址:ModularSample 本文如有什么写的错误的,请大家指正,一起进步。
使用ARouter实现组件化相关推荐
- Android组件化方案
版权声明:本文为博主原创文章,欢迎大家转载! 转载请标明出处: http://blog.csdn.net/guiying712/article/details/55213884 ,本文出自:[张华洋的 ...
- 记录一下面试考题一(组件化,ListView和RecyleView区别,App启动,Binder)
1,组件化和ARouter原理 组件化定义:由若干独立的子模块,组合成一个整体,降低模块间的耦合,这些子模块在补足一定的条件下,都可独立运行.主模块也不会因为缺少任意子模块而无法运行.组件之间可以灵活 ...
- Android 组件化方案,从入门到精通
Android组件化项目地址:Android组件化项目AndroidModulePattern Android组件化之终极方案地址:http://blog.csdn.net/guiying712/ar ...
- android 组件化_Android 组件化路由框架设计(仿Arouter)
前言 在组件化开发中一个必须要面对的问题就是组件间页面跳转,实现的方法有很多,简单的可以通过反射获取,但是比较耗费性能,也可以通过隐式跳转,但是随着页面的增多,过滤条件会随之增多,后期维护麻烦.那还有 ...
- MVVM架构结合阿里ARouter,打造一套Android-Databinding组件化
前言 关于Android的组件化,相信大家并不陌生,网上谈论组件化的文章,多如过江之鲫,然而一篇基于MVVM模式的组件化方案却很少.结合自身的调研和探索,在此分享一篇基于MVVMHabit框架(htt ...
- Android 组件化框架PPAP(直接公布源码) 绝了 感谢ARouter
组件化 通俗点就是:组件化就是基于可重用的目的,将一个大的软件系统按照分离关注点的形式,拆分成多个独立的组件,已较少耦合. 为什么要在Android中实行组件化开发 为什么要在Android中实行组件 ...
- 阿里巴巴arouter组件化总结
第1节 组件化原因 第2节 组件化须考虑的问题 第3节 ARouter使用 3.1 初始化配置 3.2 高阶使用 1. 模块间调用 2. 全局分组拦截 3. 降级处理 4. 路径替换 5. 默认Jav ...
- calces组件化与ARouter组件间通信
calces组件化与ARouter组件间通信 calces介绍: 属性介绍 ARouter(路由) https://github.com/Tangpj/calces-gradle-plugin cal ...
- android组件化架构 书,Android MVVM组件化架构方案
MVVMHabitComponent 关于Android的组件化,相信大家并不陌生,网上谈论组件化的文章,多如过江之鲫,然而一篇基于MVVM模式的组件化方案却很少.结合自身的调研和探索,在此分享一篇基 ...
最新文章
- 入门深度学习,先看看三位顶级大牛Yann LeCun、Yoshua Bengio和Geoffrey Hinton的联合综述
- 实际部署遇到的一些问题
- (转)js实现继承的5种方式
- ICCV 2019 | 厦大提出快速NAS检索方法,四小时搜索NN结构
- 小汤学编程之MySQL经典例题——表的创建与查询
- Openwrt之移动硬盘ext3/ext4格式化工具
- 电子相册系统(八)验证用户是否可用
- CentOS Linux解决Device eth0 does not seem to be pres
- 如何设置 IDEA炫酷主题样式
- echarts模拟迁徙城市重名问题
- 微信小程序tabBar的开发设置
- phpmyadmin 下载
- 关于Gary Marcus与Yann LeCun讨论AI现状及发展
- OpenGL 饱和度调节
- 2019年终总结,一朝看尽长安花
- android 修改谷歌拼音输入法全屏时的高度
- Spring Kafka实战(3)—message listener创建方式探讨
- 优雅的99乘法表以及format使用
- VSC C++ Debugging Settings
- window10安装cloc
热门文章
- 单端测序(Single end)和双端测序(Pair end和Mate pair)
- Linux操作oracle——关闭、停止、重启
- Python当前进程信息 (os包)
- CSS 解决td里面内容太多把表格弄变形的原因,设置 自动换行。
- 优秀学生是如何高效利用时间的?
- 关于页面有多个验证控件和多个按钮的问题
- 【我看Hibernate】Hibernate 介绍及其简单应用
- R—计算系统发育多样性PD (Calculate Faith’s Phylogenetic Diversity)
- html dom对象简写,js参考手册-html dom对象
- python extractor_Python pyextractor包_程序模块 - PyPI - Python中文网