两年过去了,项目中的代码越来越多了,参与的人员越来越多了,由原来的一个团队扩展成多个团队合作开发,扯皮的事也越来越多了,编译时间也从原来的20s到现在的3分钟了。于是大家开始吐槽了:
-
别的团队的同事又改了我这个类的代码,导致我这边出错
-
登录模块和个人中心一两年没有动过了,能不能这一部份代码抽出去,打个aar,我们编译也能提速
-
我主要做基础UI控件支持的,改下代码还要下载你们的项目,编译,太耗时了。我就想只调试我写的UI控件。
-
…
我们来总结以上项目迭代过程中的痛点:
-
各业务线耦合太紧,开发过程涉及到相互依赖的功能时,会有出错风险
-
部份稳定功能,长期没有迭代,但因为都在同一个库了,会拉长编译时间
-
部份功能想单独运行
-
…
所有的问题最终抛到leader这里来,于是排了一堆的技改需求:
-
项目按
首页
,商品
,订单
,个人中心
,登录
几个业务模块来分module
开发,module
之间不相互依赖, 同时收紧代码权限,这样不同团队之间就不会存在代码冲突的问题 -
登录
这个已经稳定的模块,近期不会有改动,可直接打成aar包供其它团队引入使用 -
单独定义一个module, 命名为
ui
, 整个工程中的基础UI控件,全部都放到这里来 -
定义一个module名为
common
, 为项目提供一些公共的业务资源,被其它业务模块所依赖 -
定义一个统一的内部路由,供各个组件间进行相互跳转
-
…
于是,我们可以看到,在这一堆的技改完成后,整个工程便分为了多个module
, 每一个的功能更加的单一,每个人/每个团队专注于自己的工作,也少了很多扯皮的事情,同时每一个团队都可以根据自己的业务发展实际情况,选择自己期望的技术栈。以上这些工作完成了,一个组件化的架构雏形便出来了。 我们再来细看一个组件化架构要解决哪些问题:
-
每个组件既可以是一个组件,也可以是一个application,可以单独打包调试
-
组件间的通信
-
组件间资源冲突的问题
-
组件间的跳转
manifest文件
我们期望每一个业务子module,通过配置,可以单独运行起来,此时就涉及到manifest的配置了。默认情况下,每一个module都只会有一个manifest文件,在打包阶段,打包工具会将每个module中的manifest文件合并,形成整个项目的manifest文件。比如,对于个人中心
module, 它里面有一个activity名为PersonaMainActivity
当它做作一个app运行起来的时候, 该activity是应用的入口,为此,在对应的manifest中会有类似如下代码:
但是,项目在发版的时候,个人中心
这个模块一定是作为一个子module引进来的,PersonalMainActivity
绝对不可能是整个app的入口。为此我们需要定义两套不同的manifest文件,一套是当该组件做为app运行的时采用,另一套是当该组件做为module时采用。
我们在项目的根目录定义一个文件config.gradle
, 里面定义一个变量moduleAsApp
, 当该值为false
时,代表该项目中所有的业务子module都作为组件被主module依赖,当它为true
时,代表业务子module可作为独立app运行。然后在每一个业务子module中都引入该配置。
config.gradle
文件:
ext {
moduleAsApp = false;
appId = [
“app” : “com.fred.routerapp”,
“order” : “com.fred.order”,
“product” : “com.fred.product”,
“personal” : “com.fred.personal”
]
packageNameForAPT = appId.app + “.apt”;
androidConfig = [
compileSdkVersion: 29,
buildToolsVersion: “29.0.3”,
minSdkVersion : 21,
targetSdkVersion : 29,
versionCode : 1,
versionName : “1.0”
]
}
再回到我们的个人中心module里面来,对这两种情况分别采用不同的manifest文件,如下:
sourceSets {
main {
if (moduleAsApp) {
manifest.srcFile ‘src/main/debug/AndroidManifest.xml’
} else {
manifest.srcFile ‘src/main/AndroidManifest.xml’
java {
// release 时 debug 目录下文件不需要合并到主工程
exclude ‘/debug/’
}
}
}
}
对于module配置和applicationId
if (moduleAsApp) {
apply plugin: ‘com.android.application’
} else {
apply plugin: ‘com.android.library’
}
applicationId:
if (moduleAsApp) {
applicationId appId.personal
}
在组件化开发过程中,可能会存在资源名冲突的问题,假如在product模块中有一个price_detail.xml
用来显示价格相关的视图,在order
模块中也有一个price_detail.xml
,那便会出现资源名冲突。对于这种问题,可以统一命名方式,如加前缀,将product
模块中的这些资源命名全部加上product_
前缀,order
模块中全部加上order_
前缀,这样可以一定程序上避免。当然如果只是针对于布局xml文件可以在gradle文件中进行配置来约束
android {
…
resourcePrefix “personal”
…
}
这种方式并不是说在编译的时候会手动将你的文件名进行修改,加personal_
的前缀。只是加了这个配置,如果你的命名不合法,编译器会给一个提示。
对于资源命名冲突这一块我们不仅需要关注布局文件,还有类似于color,anim, dimen等命名
此处组件间的通信主要包括两方面的内容:一种是业务之间的通知消息,比如订单模块中,一个订单提交了,需要通知购物车刷新一个购物车中的商品列表,对于这种类型的消息通知,我们可以采用EventBus,RxBus这种消息总线来做。另一个通信则是组件间基础数据的打通。比如在订单模块中,用户下单时需要判断是否登录,从单一职责的原则上讲用户的登录信息是在个人中心模块中才有。那么个人中心模块如何向其它模块提供用户相关的数据呢?
还记得我们前面提到的common
module吗?它可以被其它的所有业务子模块依赖,于是我们在common
module中定义一个接口IAccountService
public interface IAccountService {
public boolean isLogin();
…
}
在个人中心模块有它的实现类
public class AccountServiceImpl implements IAccountService {
@Override
public boolean isLogin() {
return false;
}
}
在common
模块中有一个ServiceManager
类,这个类是一个服务的管理者,它会持有一个AccountService
, 如下:
public class ServiceManager {
private ServiceManager() {}
private IAccountService accountService;
private static class AppConfigurationHolder {
private static final ServiceManager instance = new ServiceManager();
}
public static ServiceManager getInstance() {
return AppConfigurationHolder.instance;
}
public void setAccountService(IAccountService as) {
this.accountService = as;
}
public IAccountService getAccountService() {
return this.accountService;
}
}
我们期望其它模块通过调用ServiceManager.getInstance().getAccountService()
便可以拿到用户信息相关的服务。如果要达到此目的,那这个AcccountService
在什么时候注入呢?我们在再看app的架构依赖
AccountService
的实现在个人中心module,我们不确定用户在什么场景会调用这个服务。对于这种类型的服务,需要在app启动的时候便注入到app中。而AccountService
只能在个人中心模块实例化,为此个人中心模块必须要能监听到应用的初始化时机,也就是Application的onCreate
方法
监听Application的状态
在common
组件中定义一个接口, 其它的业务module都会实现这个接口。
public interface AppStateListener {
void onCreate();
void onLowMemory();
}
在个人中心模块会有一个类, 在onCreate
中会new
一个AccountService
,并且注入到ServiceManager
中
public class PersonalAppStatusListener implements AppStateListener {
@Override
public void onCreate() {
ServiceManager.getInstance().setAccountService(new AccountServiceImpl(AppStateManager.getInstance().getApplication()));
}
@Override
public void onLowMemory() {
}
}
在common
模块中,会有一个类来维护所有的子业务module对Application状态的监听
public class AppStateManager {
private List lifeCycleListenerList;
private AppStateManager(){}
private Application application;
public void init(Context context) {
this.application = (Application) context;
initAppLifeCycleListener();
}
public void initAppLifeCycleListener() {
//定义所有模块的listener的类名
String [] names = Constants.moduleLifeCycleListener;
if (names != null && names.length > 0) {
lifeCycleListenerList = new ArrayList<>();
}
for (int i = 0; i < names.length; i ++) {
try {
Class clazz = Class.forName(names[i]);
if (AppStateListener.class.isAssignableFrom(clazz)) {
lifeCycleListenerList.add((AppStateListener) clazz.newInstance());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
public Application getApplication() {
return this.application;
}
public void onCreate() {
if (lifeCycleListenerList != null) {
for (AppStateListener listener : lifeCycleListenerList) {
listener.onCreate();
}
}
}
public void onLowMemory() {
if (lifeCycleListenerList != null) {
for (AppStateListener listener : lifeCycleListenerList) {
listener.onLowMemory();
}
}
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
最后
分享一份NDK基础开发资料
分享内容包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!**
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-bPs0VlDS-1712608365075)]
最后
分享一份NDK基础开发资料
[外链图片转存中…(img-eRwN9JmJ-1712608365076)]
分享内容包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!
一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-Yu13OXaw-1712608365076)]