关于Android业务组件化的一些思考

   2016-10-09 0
核心提示:前几天在MDCC上看到冯老师关于组件化的ppt,觉得这个技术对于现今的Android开发是非常实用的,所以这几天趁着国庆假期,对其作了一点思考,以文章的形式作一个小结。通过这篇文章,希望大家能够明白,我们为什么要使用组件化,以及在进行组件化改造的时候需要

前几天在MDCC上看到冯老师关于组件化的ppt,觉得这个技术对于现今的Android开发是非常实用的,所以这几天趁着国庆假期,对其作了一点思考,以文章的形式作一个小结。通过这篇文章,希望大家能够明白,我们为什么要使用组件化,以及在进行组件化改造的时候需要注意的几个点。

关于组件化的资料:

首先关于冯老师的组件化分享,大家可以去看 这个repo ,里面是这次MDCC关于Android的一些分享。

其次,大家可以去看一下 这个repo ,是一个关于组件化的实践,我也是先看了这个demo再写的这篇文章,所以里面有很多东西是差不多的,大家也可以学习一下。

什么是组件化

在说组件化之前,相信大家对Android上的插件化肯定或多或少都有一定的了解,插件化的出现,让我们的App的运行的时候能够动态的进行组装,就像我们使用chrome的插件一样,非常的方便,甚至演变到后期,插件化越来越像[虚拟机]发展,使用一个类似[boot]的壳,就可以像Java虚拟机加载Java文件一样加载一个App。

组件化可以说和插件化有异曲同工之妙,只不过插件化是在[运行时],而组件化是在[编译时]。换句话说,插件化是基于多APK的,而组件化本质上还是只有一个APK。相信大家在平时工作中会有这样一个苦恼,那就是编译一个App的时间实在是太太太太太长了,特别是一个比较大的应用,可能2,3分钟都不够,对于一些耐心好的同学,可以去喝一杯咖啡,思考一下人生,而像我这样急性子的人嘛,简直就是噩梦,在等待编译的时候经常手足无措。[组件化]就可以很好的解决这样的问题,此外,由于整个App的各个业务被分离了,所以它们之间的耦合度也就被降低了,各个业务线可以由专门的开发同学进行开发,相互之间也不会有干扰,提升开发效率。

下面用两张图来辅助说明一下:

关于Android业务组件化的一些思考

关于Android业务组件化的一些思考

可以看到,在没有进行组件化改造的情况下,我们的App依赖的各条业务线是捆绑在一起的,根本没办法解耦,更别说模块的复用了,可以说整个App就是各条业务线混合在一起的一个大容器。

下面那张图是进行了组件化分离之后,各个业务线分离,逻辑变得清晰,每个业务线都可以成为另外一个业务线的上游或者下游。更重要的是,它们每一个都可以单独编译,缩减了编译的时间。也正因为这一点,各个业务线的研发也可以做到互相不干扰,加快了开发的速度。

如何进行组件化

对于组件化的实践,之前的方式就是各个组件以AAR的形式输出,主App去依赖那些AAR,但是这种方式,对于开发人员来说成本会有一点大,主要是以AAR形式输出的话,在每次修改之后都要重新去打一次AAR,非常的麻烦,所以冯老师提出了一种新的方式,就是以Debug模式和Release模式去区分,在Debug模式下,各个业务线作为Application可以单独运行,而在Release模式下,则作为Library,可以提供给主App进行依赖。这样一来就可以做到每个业务线的平行开发,在Release模式下再合到一起,非常的灵活。

那具体应该如何实施呢?这里以一个demo为例,让我们先看看整个as工程的结构。

关于Android业务组件化的一些思考

忽略那个moduler,它是一个gradle插件,可以看到主App就是app模块,而bizone,biztwo和bizthree代表的就是三条业务线,每一个都是一个独立的module。

然后,我们可以通过一个全局的变量去标记是Debug模式还是Release模式,当然大家也可以使用gradle的build type,但是我个人感觉还是自己设一个标记会好一点,因为这样更加灵活,对于一些混淆上的问题,我们可以通过设置Debug模式,再启用build type的release就可以去验证了。

if (isDebug.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}

通过在业务module的gradle配置文件中判断是否是Debug模式去区分是Application还是Library,这和之前提供的观点是一致的,也是这种组件化方式最核心的地方。

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:23.2.1'
testCompile 'junit:junit:4.12'
if(!isDebug.toBoolean()){
compile project(':bizone')
compile project(':biztwo')
compile project(':bizthree')
}
}

这是主App的gradle依赖,在Release模式下,直接compile那几个业务module就好了。

通过上面的操作,我们已经可以进行组件化开发了,很简单有没有。

但是需要考虑的东西还有很多。比如有一些不存在UI的业务,或者说一些业务没办法独立运行,需要一个触发源。这种情况下,最理想的方式是通过其他某个已存在的module去触发它们,或者使用一个类似于DebugActivity的东西来当作触发源,而这样的DebugOnly的东西是不应该打包到Release模式中的,所以我们需要通过gradle配置去做一些自动化的东西。

sourceSets {
main {
if (isDebug.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
java {
exclude 'debug/**'
}
}
}
}

关于Android业务组件化的一些思考

通过上面这种方式,我们就可以在Release的环境下去除掉debug包里的东西 。另外需要两个Manifest文件的原因是在Debug模式下,我们需要一个Activity标示为MAIN和LAUNCHER,而Release模式下则不需要。

关于这一点,我和冯老师也进行过沟通,下面是他的回答:

关于Android业务组件化的一些思考

还有一个问题就是,如果你想在Debug模式下使用主App去依赖业务,是没有办法通过compile的方式去实现的,因为Debug模式下各个业务线是Application,没有办法compile,这种时候,你就需要手动去将业务module的AAR添加到App中进行依赖。业务module的AAR可以在对应的build目录下找到。这个操作可以通过gradle插件去进行自动化的完成,至于怎么写对应的插件大家自己去实现吧,比较的简单。

怎么样更好的组件化

当我们完成了组件化的准备工作之后,我们需要利用一些框架或者说技术让我们的组件化之路更加完善。这里首当其冲所需要的就是URLRouter。

所谓URLRouter,就是通过类似打开网页的方式去通过路由打开一个Activity,而非直接通过显式Intent去方式去进行跳转。那是因为在进行了组件化开发之后,各个业务模块进行是可以独立运行的了,我们再使用显式Intent的方式去联系每个模块之间中间结构就会显得耦合性比较大,而且在Debug模式下也没办法使用显式Intent的方式去进行模块间的跳转。使用URLRouter的方式则可以很好的解耦,具体方法大家可以参考这篇文章里的第三种方式。

无非就是在配置Activity的时候设置一些data。

<activity android:name=".SubBizActivity">
<intent-filter>
<data
android:host="bizTwo"
android:path="/someWorks"
android:scheme="appName"/>

<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>

然后在跳转的时候使用setData的方式进行跳转。

String url = "appName://bizTwo/someWorks";
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
if (!activities.isEmpty()) {
startActivity(intent);
}

关于Android业务组件化的一些思考

就像图中所示的一样,通过URLRouter,我们就可以将业务线之间的关系解耦,互相调用也很方便。

当然要做到完善,这样的URLRouter最好是封装成一个库,减少上层的开发并且增强鲁棒性。

还有一点,通过这种方式实现组件化需要用到gradle的一些特性,比如上面说的分Debug和Release模式,在Release模式下不要编译DebugOnly的东西等等。而这样的特性我们可以通过自动化的方式去完成,而不需要开发每次新建一个module都去手写一遍。

具体的方式我这里想到的就是使用Android Studio的自定义模板。具体关于自定义模板的教程我这里不详细讲了,毕竟不是这篇文章的重点,大家可以参考 这篇文章这篇文章

对于组件化这个场景,我们所需要做的就是改写gradle.properties.ftl这个文件,添加一个isDebug属性。然后改写的build.gradle.ftl文件,添加我前面所写的那些sourceSets闭包里的代码。这些一两句话也说不清,有机会的话下次可以专门写一篇文章讲如何自定义Android Studio的模板。

关于组件化的思考

说了这么多,相信大家对组件化已经有了一个大致的概念,也知道了我们为什么要使用组件化。而在我看来,这样的技术其实对于纯开发而言难度是不大的,真正的难度在于如何剥离现有的业务线。粒度大拆分比较容易,但是不利于今后的维护。粒度小需要对业务有很深的理解,但是能很好的解耦并且提高灵活度,所以具体的情况需要在具体的实际开发中进行分析。

我的看法是组件化的前期可以先把业务线剥离的粗一点,尽管上手并且适应这样的开发,到了后期等开发熟悉了这样的形式并且对各条业务线有了很好的理解,再慢慢的细化也不迟。

 
标签: 安卓开发
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • 安卓中通知功能的具体实现
    安卓中通知功能的具体实现
    通知[Notification]是Android中比较有特色的功能,当某个应用程序希望给用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知实现。使用通知的步骤1、需要一个NotificationManager来获得NotificationManager manager = (NotificationManager
    02-05 安卓开发
  • Android view系统分析-setContentView
    Android view系统分析-setContentView
    第一天上班,列了一下今年要学习的东西。主要就是深入学习Android相关的系统源代码,夯实基础。对于学习Android系统源代码,也没什么大概,就从我们平常使用最基础的东西学起,也就是从view这个切入点开始学习Android的源码,在没分析源码之前,我们有的时候
    02-05 安卓开发
  • 如何进行网络视频截图/获取视频的缩略图
    如何进行网络视频截图/获取视频的缩略图
    小编导读:获取视频的缩略图,截图正在播放的视频某一帧,是在音视频开发中,常遇到的问题。本文是主要用于点播中截图视频,同时还可以获取点播视频的缩略图进行显示,留下一个问题,如下图所示, 如果要获取直播中节目视频缩略图,该怎么做呢?(ps:直播是直
  • Android NDK 层发起 HTTP 请求的问题及解决
    Android NDK 层发起 HTTP 请求的问题及解决
    前言新的一年,大家新年快乐~~鸡年大吉!本次给大家带来何老师的最新文章~虽然何老师还在过节,但依然放心不下广大开发者,在此佳节还未结束之际,给大家带来最新的技术分享~ 事件的起因不说了,总之是需要实现一个 NDK 层的网络请求。为了多端适用,还是选择
  • Android插件化(六): OpenAtlasの改写aapt以防止资源ID冲突
    Android插件化(六): OpenAtlasの改写aapt以防
    引言Android应用程序的编译中,负责资源打包的是aapt,如果不对打包后的资源ID进行控制,就会导致插件中的资源ID冲突。所以,我们需要改写aapt的源码,以达到通过某种方式传递资源ID的Package ID,通过aapt打包时获取到这个Package ID并且应用才插件资源的命名
    02-05 安卓开发
  • Android架构(一)MVP架构在Android中的实践
    Android架构(一)MVP架构在Android中的实践
    为什么要重视程序的架构设计 对程序进行架构设计的原因,归根结底是为了 提高生产力 。通过设计是程序模块化,做到模块内部的 高聚合 和模块之间的 低耦合 (如依赖注入就是低耦合的集中体现)。 这样做的好处是使得程序开发过程中,开发人员主需要专注于一点,
    02-05 安卓开发
  • 安卓逆向系列教程 4.2 分析锁机软件
    安卓逆向系列教程 4.2 分析锁机软件
    安卓逆向系列教程 4.2 分析锁机软件 作者: 飞龙 这个教程中我们要分析一个锁机软件。像这种软件都比较简单,完全可以顺着入口看下去,但我这里还是用关键点来定位。首先这个软件的截图是这样,进入这个界面之后,除非退出模拟器,否则没办法回到桌面。上面那
    02-05 安卓开发
  • Android插件化(二):OpenAtlas插件安装过程分析
    Android插件化(二):OpenAtlas插件安装过程分析
    在前一篇博客 Android插件化(一):OpenAtlas架构以及实现原理概要 中,我们对应Android插件化存在的问题,实现原理,以及目前的实现方案进行了简单的叙述。从这篇开始,我们要深入到OpenAtlas的源码中进行插件安装过程的分析。 插件的安装分为3种:宿主启动时立
    02-05 安卓开发
  • [译] Android API 指南
    [译] Android API 指南
    众所周知,Android开发者有中文网站了,API 指南一眼看去最左侧的菜单都是中文,然而点进去内容还是很多是英文,并没有全部翻译,我这里整理了API 指南的目录,便于查看,如果之前还没有通读,现在可以好好看一遍。注意,如果标题带有英文,说明官方还没有翻
  • 使用FileProvider解决file:// URI引起的FileUriExposedException
    使用FileProvider解决file:// URI引起的FileUri
    问题以下是一段简单的代码,它调用系统的相机app来拍摄照片:void takePhoto(String cameraPhotoPath) {File cameraPhoto = new File(cameraPhotoPath);Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);takePhotoIntent.putExtra(Medi
    02-05 安卓开发
点击排行