关于Android组件化的深度分析篇初探组件化
Posted 初一十五啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Android组件化的深度分析篇初探组件化相关的知识,希望对你有一定的参考价值。
theme: mk-cute
前言
😥好难,身边两朋友一红黄,只有我还是绿码,都不敢一起玩了。
今天来简介下组件化的诞生→组件化演示案例→组件化项目实战(附demo)
关注公众号:初一十五a
解锁 《Android十二大板块PDF》
音视频大合集,从初中高到面试应有尽有;让学习更贴近未来实战。已形成PDF版
十二个模块PDF内容如下:
1.2022最新Android11位大厂面试专题,128道附答案
2.音视频大合集,从初中高到面试应有尽有
3.Android车载应用大合集,从零开始一起学
4.性能优化大合集,告别优化烦恼
5.Framework大合集,从里到外分析的明明白白
6.Flutter大合集,进阶Flutter高级工程师
7.compose大合集,拥抱新技术
8.Jetpack大合集,全家桶一次吃个够
9.架构大合集,轻松应对工作需求
10.Android基础篇大合集,根基稳固高楼平地起
11.Flutter番外篇:Flutter面试+项目实战+电子书
12.大厂高级Android组件化强化实战
整理不易,关注一下吧。开始进入正题,ღ( ´・ᴗ・` ) 🤔
第二章:初探组件化
一丶组件化的诞生
随着对大型APP的重构计划,我们需要这样一个框架:
- 支持大量丰富业务的接入,同时业务之间能够保持清晰的边界,各自可以继续灵活迭代;
- 用一批统一的中间件去支撑起各种业务的底层功能,保持中间件代码的全面复用;
- 能够尽量保持对系统的低侵入,尊重原生运行机制以降低后期的维护成本;
- 在用户设备上尽量体现一个简单客户端的特性,同时特定的业务功能按需获取,保持体积的可控;
↑新容器化结构设想↑
基于对插件化框架对android运行机制的理解,参考了OSGI在服务端框架,在开发IDE等领域"高复用、低耦合、可插拔"的优势,我们借鉴了OSGI规范开发了基于组件化的Atlas容器化框架。
下图是基于组件化框架的系统结构:
最底层的tookit verifier全面罗列了上层需要反射使用的注入和代理的Api,会在应用启动时先进性全局性的校验,以避免程序运行中遇到不兼容的情况;
往上Bundle Framework负责组件的安装 更新 操作以及管理所有组件的生命周期,这里组件的边界隔离就遵循了OSGI的规范,每个组件分配独立的classloader,同时组件有各自的资源,每个资源在构建期间由AAPT分配独立的package ID;
Runtime层 主要包括清单管理、版本管理、以及系统代理三大块:
- 版本:每个组件在构建期间就由构建插件分配自己的版本号,同时安装期间也有各自的版本目录,每个bundle的启动加载都需要经过版本的校验,组件发生更新同时也下发最新的版本信息。依托版本管理机制组件的热更新能力水到渠成。
- 清单:OSGI规范中每个组件通常通过OSGI.MF来暴露自身的component,这是与Atlas容器所不同的地方。在Android设备上,多文件的形式很容易受IO异常的影响干扰bundle正常运行,所以我们采用了构建期间集中生成清单的方式,清单里面记录bundle所有的component(Android四大组件),依赖、packagename等内容。
- 代理:各个系统关键点的注入使得bundle可以做到按需加载,避免了像原生MultiDex方案由于首次启动时多dex同步安装而造成UI卡顿的情况,代理层的核心DelegateClassLoader负责类的查找和路由,DelegateResource管理所有bundle的资源,它们在容器启动时进行注入,并在运行过程中随着bundle的不断载入进行更新。
接入层 简单是美-复杂的东西留给自己。为了方便,Atlas容器有自身独立的Application负责启动,同时在构建期间会由插件替换应用原有的Application。运行期间应用首先由AtlasBridgeApplication负责启动,并在容器启
动完毕后全权代理给应用真正的Application;同时对需要自定义和由外部决策的功能,容器开放接口由接入方简单设置。
二丶组件化演示案例
2.1概述
软件开发进程也是架构的演进过程,就拿Android来说,从最开始的MVC ,MVP ,MVVP ,再到后来的组件化,插件化,但归根到底一切的一切,都是为了项目更好的维护、迭代,降低开发成本。
在一个项目的开发过程中,前期我们可能把所有的功能模块都放到了一个moudle中,这样能够快速的开发,但随着项目壮大,开发人员和功能的增加,就回导致代码越来越臃肿,各个模块之间的耦合越来越重,牵一发而动全身,这个时候为了保证项目质量,我们就需要对项目进行重构。
我们可以根据业务模块进行查分,把不同的业务模块放到不同的moudle中,实现各个业务之间的结构,他们又共同依赖底层公共库,这就是模块化的概念,但是当多个模块中涉及到相同功能时代码的耦合又会增加,例如有两个模块都需要视频播放的功能,把视频播放放到两个组件中就会出现代码重复的问题,放到公共库感觉也不是很好,这时候就用组件化来解决这个问题
2.2.模块化和组件化
模块化
具体的业务模块,例如商品详情模块,商品发布模块 ,搜索模块
组件化
单一的功能组件,如视频播放组件、分享组件等,每个组件都可以以一个单独的 module 开发,并且可以单独抽出来作为 SDK 对外发布使用
模块化和组件化的思想是一样的,都是对代码进行拆分,但模块化是按功能模块进行查分(业务导向),组件化是按功能模块进行查分(功能导向),模块化的颗粒度更大一些,组件的颗粒度更小一些,一个项目中模块和组件同时存在也是很常见的,各自负责各自的事情。
如上图所示 是个组件化项目的基本架构
- 基础库、公共库:项目所需要的基础操作类,工具类 ,第三方库的引入封装 ,app宿主功能,各个模块,各个组件都依赖这个库
- 组件层:项目用的功能模块或者业务模块,如:登录模块,视频播放组件,分享组件等
- 应用层:宿主工程,APP的主项目,APP入口和主架子
2.3.组件化Demo
demo前面有,我根据demo项目从以下几个方面来讲解
- 项目分析
- 组件application和library动态切换
- 组件间的数据传递和方法调用
- 组件类(例如:Fragment)的获取,以及夸组件页面跳转和通讯
项目分析
如上图所示,项目的主要结构
- 应用层:app 项目的主入口
- 组件层:goods login 商品详情页和登录组件
- 基础库层:assemblebase用来各个组件数据和方法交互的 ,base是常用的工具类,各种类库的封装
组件application和library动态切换
在开发过程中,为了能够实现快速开发,组件能够独立运行就显的特别重要,moudle一般分为两种:
- App 插件,id: com.android.application
- Library 插件,id: com.android.library
我们可以通过配置可动态进行application和library的切换,我们在各个组件的gradle.properties文件中配置一个控制切换的变量
然后在build.gradle中就可以通过isRunAlone变量来进行application和library的切换了,主要设计的点有三部分
- plugin属性的配置
- applicationId的配置
- AndroidManifest的配置
if (isRunAlone.toBoolean())
apply plugin: 'com.android.application'
else
apply plugin: 'com.android.library'
android
compileSdkVersion 26
defaultConfig
if (isRunAlone.toBoolean())
applicationId "ppzh.jd.com.goods"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
buildTypes
release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguardrules.pro'
sourceSets
main
if (isRunAlone.toBoolean())
manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
else
manifest.srcFile 'src/main/AndroidManifest.xml'
如果以上配置就可以实现application和library的切换了
组件间的数据传递和方法调用
由于主项目、组件之间,组件和组件之间不能直接通过引用进行数据传递和方法调用,那么在开发的过程中怎么进行数据传递和方法调用呢,可以通过「接口」+「实现」的方式进行,
assemblebase基础库就是用来进行数据传递和方法调用的,它被所有组件所依赖,assemblebase提供各个组件对外提供数据和方法调用的抽象service ,同时还有serviceFactory对service进行操作,各个组件在初始化的时候对各自的service进行实现。同时中也会提供所有的 Service 的空实现,以避免引起的空指针异常
就以登录模块为例,对外提供两个数据
public interface ILoginService
/**
* 是否已经登录
*
* @return
*/
boolean isLogin();
/**
* 获取登录用户的 AccountId
*
* @return
*/
String getAccountId();
相关的serviceFactory类如下,可以通过serviceFactory拉取相关service的实例
public class ServiceFactory
private ILoginService loginService;
private IGoodsService goodsService;
/**
* 禁止外部创建 ServiceFactory 对象
*/
private ServiceFactory()
/**
* 通过静态内部类方式实现 ServiceFactory 的单例
*/
public static ServiceFactory getInstance()
return Inner.serviceFactory;
private static class Inner
private static ServiceFactory serviceFactory = new ServiceFactory();
// ------------------------LoginService------------------------
/**
* 接收 Login 组件实现的 Service 实例
*/
public void setLoginService(ILoginService loginService)
this.loginService = loginService;
/**
* 返回 Login 组件的 Service 实例
*/
public ILoginService getLoginService()
if (loginService == null)
loginService = new EmptyLoginService();
return loginService;
在login组件中只需要实现ILoginService,并通过serviceFactory进行设置
public class LoginService implements ILoginService
@Override
public boolean isLogin()
return false;
@Override
public String getAccountId()
return null;
在login的appliction中进行service的设置
public class LoginApp extends BaseApp
@Override
public void onCreate()
super.onCreate();
initModuleApp(this);
initModuleData(this);
@Override
public void initModuleApp(Application application)
ServiceFactory.getInstance().setLoginService(new LoginService());
@Override
public void initModuleData(Application application)
但是有这样一个问题:在集成到app中,LoginApp是没有被执行的,这个怎么解决呢,我们可以通过反射进行解决
public class AssembleApplication extends BaseApp
@Override
public void onCreate()
super.onCreate();
initModuleApp(this);
initModuleData(this);
initComponentList();
@Override
public void initModuleApp(Application application)
@Override
public void initModuleData(Application application)
//初始化组件
//通过反射初始化
private void initComponentList()
for (String moduleApp : AppConfig.moduleApps)
try
Class clazz = Class.forName(moduleApp);
BaseApp baseApp = (BaseApp) clazz.newInstance();
baseApp.initModuleApp(this);
baseApp.initModuleData(this);
catch (Exception e)
e.printStackTrace();
如上所示就完成了
组件类(例如:Fragment)的获取,以及夸组件页面跳转和通讯
fragment的获取也是通过service来完成的
public interface IGoodsService
/**
* 创建 GoodsFragment
* @param bundle
* @return
*/
Fragment newGoodsFragment(Bundle bundle);
相关组件实现该接口就行
各个组件间页面的跳转可以通过阿里的ARouter实现,我是通过设置ComponentName来实现的,但这种方式好像并没有实现真正的代码隔离
/**
*
* 去登陆
*
* 跨组件页面跳转
*/
private void toLogin()
Intent intent = new Intent();
intent.setComponent(new ComponentName(mContext, "ppzh.jd.com.login.LoginActivity"));
startActivityForResult(intent,LOGIN_REQUEST_CODE);
总结
通过上面就整体实现了项目组件化,在以后也可以更多的运用组件化来进行项目开发
三丶wanAndroid APP组件化项目实战
3.1.简介
本项目基于 组件化 + Arouter + Jetpack + Rxjava + Retrofit + AOP 等框架实现的一款开源项目。
3.2.版本更新
module单独编译运行
module-main迁移至app,并移除module-main
效果图
主要功能:
- 首页、项目、广场、公众号、我的
- 登录、注册 动画交互
- 搜索页面共享元素动画过渡
- 项目页面仿高德地图滑动面板交互
- 广场页面tab跟随滑动系数渐变、列表采用谷歌爸爸的flexboxlayout流式布局
- 广场页面根据滑动系数给indicator添加动画效果
- 公众号页面点击左上角为一个90°的arc交互动画,列表数据从下往上过渡的动画效果
- 我的页面仿百度外卖个人中心水波纹效果
- 整体采用Material Design设计风格
项目目录结构
|- WanAndroid
||-- app // app 入口
||librarys //library库
||--library-aop// aop 封装(登录校验、点击)
||--library-db// room数据库封装
||--library-network// 网络请求封装(livedata+rxjava+retrofit)
||--library-base// 基础封装(BaseAc、BaseFg、BaseUtil等)
||--library-common//共用的组件、适配器、api返回实体类等
||--library-widget// 控件封装
||--modules// 功能模块
||--module-home// 首页模块
||--module-login// 登录模块
||--module-project// 项目模块
||--module-square // 广场模块
||--module-public //公众号模块
||--module-mine//我的模块
||--module-web//网页模块
||-- README.md
module单独编译运行说明
gradle.properties 文件下有个"集成开发模式" 和 "组件开发模式"的切换开关 true表示组件独立运行,false表示一个library
isRunModule=true
主要开源框架
-
flexbox-layout
-
RxJava
-
RxAndroid
-
Retrofit
-
okhttp
-
Glide
-
BaseRecyclerViewAdapterHelper
-
EventBus
-
Arouter
-
ImmersionBar
-
particle
-
banner
-
Loadsir
-
MagicIndicator
-
MMKV
-
SmartRefreshLayout
-
AgentWeb
-
aop
-
persistentcookieJar
-
下文:从各大厂看组件化架构实践
关注公众号:初一十五a
解锁 《Android十二大板块PDF》
音视频大合集,从初中高到面试应有尽有;让学习更贴近未来实战。已形成PDF版
十二个模块PDF内容如下:
1.2022最新Android11位大厂面试专题,128道附答案
2.音视频大合集,从初中高到面试应有尽有
3.Android车载应用大合集,从零开始一起学
4.性能优化大合集,告别优化烦恼
5.Framework大合集,从里到外分析的明明白白
6.Flutter大合集,进阶Flutter高级工程师
7.compose大合集,拥抱新技术
8.Jetpack大合集,全家桶一次吃个够
9.架构大合集,轻松应对工作需求
10.Android基础篇大合集,根基稳固高楼平地起
11.Flutter番外篇:Flutter面试+项目实战+电子书
12.大厂高级Android组件化强化实战
整理不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔
以上是关于关于Android组件化的深度分析篇初探组件化的主要内容,如果未能解决你的问题,请参考以下文章