前言

好难,身边两朋友一红黄,只有我还是绿码,都不敢一同玩了。

今天来简介下组件化的诞生→组件化演示事例→组件化项目实战(附demo)

关注公众号:Android苦做舟 解锁 《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组件化的深度分析篇(二)初探组件化
↑新容器化结构设想↑

依据对插件化结构对Android运转机制的理解,参考了OSGI在服务端结构,在开发IDE等领域”高复用、低耦合、可插拔”的优势,咱们借鉴了OSGI规范开发了依据组件化的Atlas容器化结构。

下图是依据组件化结构的系统结构:

关于Android组件化的深度分析篇(二)初探组件化
最底层的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;一起对需求自定义和由外部决议计划的功用,容器开放接口由接入方简略设置。

二丶组件化演示事例

demo

2.1概述

软件开发进程也是架构的演进进程,就拿Android来说,从最开始的MVC ,MVP ,MVVP ,再到后来的组件化,插件化,但归根结底一切的一切,都是为了项目更好的保护、迭代,下降开发本钱。

在一个项目的开发进程中,前期咱们可能把一切的功用模块都放到了一个moudle中,这样能够快速的开发,但随着项目壮大,开发人员和功用的添加,就回导致代码越来越臃肿,各个模块之间的耦合越来越重,牵一发而动全身,这个时分为了保证项目质量,咱们就需求对项目进行重构。

咱们能够依据事务模块进行查分,把不同的事务模块放到不同的moudle中,完成各个事务之间的结构,他们又一起依靠底层公共库,这便是模块化的概念,但是当多个模块中涉及到相同功用时代码的耦合又会添加,例如有两个模块都需求视频播映的功用,把视频播映放到两个组件中就会出现代码重复的问题,放到公共库感觉也不是很好,这时分就用组件化来处理这个问题

2.2.模块化和组件化

模块化 详细的事务模块,例如产品详情模块,产品发布模块 ,查找模块

组件化 单一的功用组件,如视频播映组件、分享组件等,每个组件都能够以一个独自的 module 开发,而且能够独自抽出来作为 SDK 对外发布运用

模块化和组件化的思想是一样的,都是对代码进行拆分,但模块化是按功用模块进行查分(事务导向),组件化是按功用模块进行查分(功用导向),模块化的颗粒度更大一些,组件的颗粒度更小一些,一个项目中模块和组件一起存在也是很常见的,各自担任各自的工作。

关于Android组件化的深度分析篇(二)初探组件化
如上图所示 是个组件化项目的根本架构

  • 根底库、公共库:项目所需求的根底操作类,东西类 ,第三方库的引进封装 ,app宿主功用,各个模块,各个组件都依靠这个库
  • 组件层:项目用的功用模块或者事务模块,如:登录模块,视频播映组件,分享组件等
  • 运用层:宿主工程,APP的主项目,APP进口和主架子

2.3.组件化Demo

demo前面有,我依据demo项目从以下几个方面来解说

  • 项目剖析
  • 组件application和library动态切换
  • 组件间的数据传递和办法调用
  • 组件类(例如:Fragment)的获取,以及夸组件页面跳转和通讯

项目剖析

关于Android组件化的深度分析篇(二)初探组件化
如上图所示,项目的首要结构

  • 运用层:app 项目的主进口
  • 组件层:goods login 产品详情页和登录组件
  • 根底库层:assemblebase用来各个组件数据和办法交互的 ,base是常用的东西类,各种类库的封装

组件application和library动态切换 在开发进程中,为了能够完成快速开发,组件能够独立运转就显的特别重要,moudle一般分为两种:

  • App 插件,id: com.android.application
  • Library 插件,id: com.android.library

咱们能够经过装备可动态进行application和library的切换,咱们在各个组件的gradle.properties文件中装备一个操控切换的变量

关于Android组件化的深度分析篇(二)初探组件化
然后在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

关于Android组件化的深度分析篇(二)初探组件化
作用图

关于Android组件化的深度分析篇(二)初探组件化

关于Android组件化的深度分析篇(二)初探组件化
首要功用

  • 主页、项目、广场、公众号、我的
  • 登录、注册 动画交互
  • 查找页面共享元素动画过渡
  • 项目页面仿高德地图滑动面板交互
  • 广场页面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

  • 下文:从各大厂看组件化架构实践

关注公众号:Android苦做舟 解锁 《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组件化强化实战

整理不易,关注一下吧。ღ( ・ᴗ・` )