android sdk方法隐藏_每个Android开发都必须知道的利器

1.背景介绍

  在移动端项目功能不断完善和丰富的过程中我们一直在寻找一种可以高效开发且复用率高的开发模式,特别是多应用同步开发、管理。

  在开发过程中你是否遇到需要发布影子工程?新建项目是否需要耗费大量时间将原有基类、工具类、第三方通用类库逐个 copy 进新项目中?在项目不断迭代后是否发现编译时间不断增加?

  组件化开发可以很好的解决上述问题,它实际是将一个完整的项目划分为若干个模块,过程类似搭积木,一个一个拼接,你可以单独使用其中任意一个,也可以用多个拼接出各种形状,达到高效开发,最大复用。

在了解组件化开发之前我们需要先了解组件和模块这两个概念

  • 组件:指的是单一的功能组件,如地图组件(MapSDK)、支付组件(AnjukePay)、路由组件(Router)等等;

  • 模块:指的是独立的业务模块,如基类模块(common-module)、商城模块(mall-module)、会员模块(member-module)等等;模块相对于组件来说粒度更大。

2.系统架构图

5bd2b77f8b9dd021850c619d2a7c2c99.png

abd1c4530dbece39cfbf03240cdddc32.png

项目由主项目 app,商城模块 mall-module,会员模块 member-module,公共模块 common-module 各个基类(BaseActivity/BaseApplication/BaseAdapter 等)、工具类、网络、图片等一些公共常用的第三方 sdk:

  • app:作为项目的主程序入口,生产环境时可以引入其他模块如本项目的的 common-module、mall-modulem、member-module;开发调试不涉及到跨模块调用业务时可以单独引入 common-module 依赖运行。

  • mall-module:商城模块,编写完整的商城业务逻辑,生产环境作为 library 引入 app 主项目,开发阶段可以 application 方式单独运行,亦可作为商城应用独立发布。

  • member-module:会员模块,编写完整的会员业务逻辑,生产环境作为 library 引入 app 主项目,开发阶段可以 application 方式单独运行,亦可作为会员独立发布。

  • common-module:作为整个项目的基石,所有基类增加修改,均可以在引入项目中生效,达到最大复用率,提高开发效率。

3.实践

mall-module、member-module、common-module 作为 library 被引入 app 中运行效果图:

12729d7163cb2dd9866f6bc647352627.png

mall-module 作为应用单独运行效果图:

f719e8f9dc330e97e3d796d0994f7405.png

主项目 app 创建 项目 build.gradle 配置文件:

apply plugin: 'com.alibaba.arouter'

buildscript {

   repositories {

       google()

       jcenter()

   }

   dependencies {

       classpath 'com.android.tools.build:gradle:2.3.3'

       classpath "com.alibaba:arouter-register:1.0.2"

   }

}

allprojects {

   repositories {

       google()

       jcenter { url "http://jcenter.bintray.com/" }

   }

}

task clean(type: Delete) {

   delete rootProject.buildDir

}

项目 gradle.properties 全局配置文件:

#IS_MAIN_APP true主项目为应用 mall-module为library false mall-module为应用可单独启动

IS_MAIN_APP=true

#AS 编译配置

COMPILE_SDK_VERSION=28

BUILDTOOLS_VERSION=28.0.3

MIN_SDK_VERSION=15

TARGET_SDK_VERSION=25

#版本号

APP_VERSION=1

APP_VERSION_CODE=1.0.1

app build.gradle 配置文件:apply plugin 根据 ISMAINAPP 值设置为 application 或 library

if (IS_MAIN_APP.toBoolean()) {

   apply plugin: 'com.android.application'

} else {

   apply plugin: 'com.android.library'

}

android {

   compileSdkVersion Integer.parseInt(COMPILE_SDK_VERSION)

   buildToolsVersion BUILDTOOLS_VERSION

   defaultConfig {

       if (IS_MAIN_APP.toBoolean()) {

           applicationId "com.fenlibao.arouter"

       }

       minSdkVersion Integer.parseInt(MIN_SDK_VERSION)

       targetSdkVersion Integer.parseInt(TARGET_SDK_VERSION)

       versionCode Integer.parseInt(APP_VERSION)

       versionName APP_VERSION_CODE

       testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

       javaCompileOptions {

           annotationProcessorOptions {

               arguments = [AROUTER_MODULE_NAME: project.getName(), AROUTER_GENERATE_DOC: "enable"]

           }

       }

   }

   buildTypes {

       release {

           minifyEnabled false

           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

       }

   }

   sourceSets {

       main {

           if (IS_MAIN_APP.toBoolean()) {

               manifest.srcFile 'src/main/release/AndroidManifest.xml'

           } else {

               manifest.srcFile 'src/main/debug/AndroidManifest.xml'

           }

       }

   }

}

dependencies {

   compile fileTree(dir: 'libs', include: ['*.jar'])

   annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'

   compile project(':common-module')//公共方法 基类 放在该项目中

   if (IS_MAIN_APP.toBoolean()) {

       compile project(':mall-module')//商城模块

       compile project(':member-module')//会员模块

   }

}

创建 mall-module: mall-module build.gradle 配置文件 apply plugin 根据 ISMALLAPP 值设置为 application 或 library

if (IS_MALL_APP.toBoolean()) {

   apply plugin: 'com.android.application'

} else {

   apply plugin: 'com.android.library'

}

android {

   compileSdkVersion Integer.parseInt(COMPILE_SDK_VERSION)

   buildToolsVersion BUILDTOOLS_VERSION

   defaultConfig {

       if (IS_MALL_APP.toBoolean()) {

           applicationId "com.fenlibao.mall"

       }

       minSdkVersion Integer.parseInt(MIN_SDK_VERSION)

       targetSdkVersion Integer.parseInt(TARGET_SDK_VERSION)

       versionCode Integer.parseInt(APP_VERSION)

       versionName APP_VERSION_CODE

       testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

       resourcePrefix "mall_"

       javaCompileOptions {

           annotationProcessorOptions {

               arguments = [AROUTER_MODULE_NAME: project.getName()]

           }

       }

   }

   buildTypes {

       release {

           minifyEnabled false

           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

       }

   }

   sourceSets {

       main {

           if (IS_MALL_APP.toBoolean()) {

               manifest.srcFile 'src/main/release/AndroidManifest.xml'

           } else {

               manifest.srcFile 'src/main/debug/AndroidManifest.xml'

           }

       }

   }

}

dependencies {

   compile project(':common-module')

   compile 'com.android.support.constraint:constraint-layout:1.1.3'

   annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'

}

common-module 创建: common-module build.gradle 配置文件 apply plugin 固定为'com.android.library'作为库被其他项目引用

apply plugin: 'com.android.library'

android {

   compileSdkVersion Integer.parseInt(COMPILE_SDK_VERSION)

   buildToolsVersion BUILDTOOLS_VERSION

   defaultConfig {

       minSdkVersion Integer.parseInt(MIN_SDK_VERSION)

       targetSdkVersion Integer.parseInt(TARGET_SDK_VERSION)

       versionCode Integer.parseInt(APP_VERSION)

       versionName APP_VERSION_CODE

       testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

       javaCompileOptions {

           annotationProcessorOptions {

               arguments = [ AROUTER_MODULE_NAME : project.getName() ]

           }

       }

   }

   buildTypes {

       release {

           minifyEnabled false

           proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

       }

   }

}

dependencies {

   compile fileTree(dir: 'libs', include: ['*.jar'])

   compile 'com.android.support:appcompat-v7:28.0.0'

   compile 'com.android.support:design:28.0.0'

   compile 'com.android.support.constraint:constraint-layout:1.1.3'

   testCompile 'junit:junit:4.12'

   androidTestCompile 'com.android.support.test:runner:1.0.2'

   androidTestCompile('com.android.support.test.espresso:espresso-core:3.0.2', {

       exclude group: 'com.android.support', module: 'support-annotations'

   })

   compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'

//该项目中suppourt包为25.2.0版本比较低 顾做排除处理

   compile('com.alibaba:arouter-api:1.4.1') {

       exclude group: 'com.android.support'

   }

   //Rxjava2

   compile 'io.reactivex.rxjava2:rxjava:2.2.6'

   compile 'io.reactivex.rxjava2:rxandroid:2.1.0'

   //Retrofit2

   compile 'com.squareup.retrofit2:retrofit:2.4.0'

   compile 'com.squareup.retrofit2:converter-gson:2.4.0'

   compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

   //Okhttp-interceptor

   compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'

}

4.注意事项

多个 module 间 Activity 如何跳转?

31782a33553ea5bd5245d30fb18dff14.png

由于模块与模块之间是相互独立存在,因而不能使用项目内方式实现 Activity 跳转,下面介绍两种 Activity 跳转方式,日常开发中推荐使用方式二,方式二不管如何修改类名包名都能保持与字符串常量映射关系,维护和使用更方便,更多 ARouter 高级用法请查阅相关资料。

通过反射方式:

try {

   Class clazz = Class.forName("com.fenlibao.member.MainActivity");

   Intent intent = new Intent(_activity, clazz);

   startActivity(intent);

} catch (ClassNotFoundException e) {

   e.printStackTrace();

}

使用 ARouter 注解方式,实现映射关系自动注册:

/**

* ARouter在MyApplication中初始化

*/

public class MyApplication extends BaseApplication {

   @Override

   public void onCreate() {

       super.onCreate();

       init();

   }

   private void init() {

       if (isDebug()) {

           ARouter.openLog();

           ARouter.openDebug();

       }

       ARouter.init(this);

   }

   public boolean isDebug() {

       return getApplicationInfo() != null && (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;

   }

   @Override

   public void onTerminate() {

       super.onTerminate();

       ARouter.getInstance().destroy();

   }

}

/**

* 在常量类中定义静态字符串常量

*/

public static final String MEMBER_1_URL_MAIN = "/member/MainActivity";

/**

* 在对应module Activity中使用@Route标签进行绑定

*/

@Route(path = RoutePath.MALL_1_URL_MAIN)

public class MainActivity extends BaseActivity {

}

/**

* 在需要跳转至该页面build方法中传入对应Activity字符串常量,即可实现跳转

*/

ARouter.getInstance().build(RoutePath.MEMBER_1_URL_MAIN).navigation();

在 module 中如何获取 Application 上下文对象?

在 common-module 中定义 BaseApplication 继承 Application。

**

* 项目Application基类主项Application需集成此类

*/

public class BaseApplication extends Application {

   /**

    * 系统上下文

    */

   private static BaseApplication mAppContext;

   @Override

   public void onCreate() {

       super.onCreate();

       mAppContext = this;

   }

   /**

    * 获取系统上下文单例

    */

   public static BaseApplication getInstance() {

       return mAppContext;

   }

}

在 app 项目中 MyApplication(上部分代码示例中可以查看)继承 BaseApplication,同时设置到 AndroidManifest.xml application 标签下 name 属性中。

在 app 及 module 中都可通过 BaseApplication.getInstance();方法即可获取应用上下文对象,如下:

BaseApplication application = BaseApplication.getInstance();

如何将 module 作为应用单独运行?

在项目 gradle.properties 全局配置文件中找到 ISMAINAPP 配置变量,设置为 ture 时为主项目启动方式,设置为 false,脱离其他 mall-module 作为应用单独启动,设置完成之后重新编译项目即可,开发测试阶段推荐使用该方式,可缩短项目编译时间,项目越大,缩短时间越明显。

##IS_MAIN_APP true主项目为应用,mall-module为library;false mall-module为应用可单独启动

IS_MAIN_APP=true

应用主入口只能有一个,如何切换应用主入口?

根据 ISMAINAPP 设置值加载不同目录下的 AndroidManifest.xml 文件,实现根据参数加载配置文件,下面是 app mall-module 的 build.gradle 配置。

#app build.gradle

android {

   sourceSets {

           main {

               if (IS_MAIN_APP.toBoolean()) {

                   manifest.srcFile 'src/main/release/AndroidManifest.xml'

               } else {

                   manifest.srcFile 'src/main/debug/AndroidManifest.xml'

               }

           }

       }

}

#mall-module build.gradle

android {

   sourceSets {

           main {

               if (!IS_MAIN_APP.toBoolean()) {

                   manifest.srcFile 'src/main/release/AndroidManifest.xml'

               } else {

                   manifest.srcFile 'src/main/debug/AndroidManifest.xml'

               }

           }

       }

}

如何避免资源文件冲突覆盖?

在组件化开发过程中经常会出现资源文件冲突覆盖问题,主项目会覆盖 module 项目资源文件。

在 module 项目中 build.gradle 配置文件中设置:

resourcePrefix "mall_"

  1. 通过给模块设置不同的前缀,避免资源文件重名覆盖问题。

  2. 良好的命名(资源文件/类文件)习惯,需以 module 前缀开头,例如 mall-module 布局资源文件,采用 mallactivity_home,方式避免资源文件重名覆盖问题,如果资源文件不按 resourcePrefix "mall" 定义前缀命名会有错误提示,例如以如下方式命名布局资源文件 activitymallhome.xml:

04efa3f503a8f9183ecbcead28ced0b5.png

组件化开发如何利用 Git 管理代码,实现协同开发?

项目中引用的 module 可能是其他组员负责开发,我们只负责调用传递数据,当 module 发生改变时,项目中需要可以获取到最新的代码,本项目中采用 git submodule 方式管理代码,如下图:

04dae67c9e02f5aaba12ed8dae8497ad.png

1. 增加 git module 项目引用 采用 git submodule add [url][module-name] 命令增加 git 项目引用 url:git 项目完整路径; module-name:为本地项目 module 名称

2. 导入完整 git submodule 项目 第一步初始化:git submodule init;第二步更新项目:git submodule update 引用至本地,如果遇到提示项目目录已存在,将原有项目目录删除再执行更新命令即可。

5.总结

  以上就是组件化开发的详细步骤和相关注意事项,如果你面前是一个庞大的工程,建议你使用该方案,以最小的代价尽快开始实施组件化。如果你现在负责的是一个开发初期的项目,代码量还不大,那么也建议尽快进行组件化的规划,不要给未来的自己增加徒劳的工作量。 项目示例 Github 地址:https://github.com/guixia/Android-Submodule.git。

- END -

aa8a9929b9f34be840b9210ad36af684.png

更多推荐内容

a7a48253fa09a616826b2822d37a22de.gif

《kubernetes 单master集群的搭建》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/562083.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

❤️六W字《计算机基础知识》(七)(建议收藏)❤️

在Word中,对某个段落的全部文字进行下列设置,属于段落格式设置的是____。 A、设置为四号字 B、设置为楷体字 C、设置为1.5倍行距 D、设置为4磅字间距 用Word编辑文件时,用户可以设置文件的自动保存时间间隔。如果改变自动保存时…

flash 火狐总是崩溃_win10系统火狐flash插件总是崩溃的解决方法

win10系统火狐flash插件总是崩溃的问题发生概率较高。怎样来处理win10系统火狐flash插件总是崩溃的问题,知道的人估计不多。本站针对win10系统火狐flash插件总是崩溃的情况总结了一些解决的方法。简单说两步:1、在火狐浏览器地址栏在输入:abo…

❤️六W字《计算机基础知识》(八)(建议收藏)❤️

在Word中替换的快捷键是____。 A、CTRLF B、CTRLH C、CTRLS D、CTRLP 在Word中打印的快捷键是____。 A、CTRLF B、CTRLH C、CTRLO D、CTRLP 在Word中打开新文档的快捷键是____。 A、CTRLF B、CTRLH C、CTRLO D、CTRLP 在Word中,___最大。 A、初…

s3vm与tritraining_S3FD论文解读

论文题目:S3FD: Single Shot Scale-invariant Face DetectorS$^3$FD: Single Shot Scale-invariant Face Detector​arxiv.orgsfzhang15/SFD​github.com作者团队,来自于中科院自动化所(CASIA),一作Shifeng Zhang(张士峰),看见没&…

❤️六W字《计算机基础知识》(九)(建议收藏)❤️

在PowerPoint2000中,若为幻灯片中的对象设置"飞入",应选择对话框____。 A、自定义动画 B、幻灯片版式 C、自定义放映 D、幻灯处放映 在编辑Word文档时,输入的新字符总是覆盖了文档中已经输入的字符,_____。 A、原因是…

mysql怎么创建表_mysql怎么创建一个表

1.登陆成功后,首先进入某一个数据库 (不是指数据库服务器)use t1; //t1是数据库名如图所示:2.在此数据库中建立数据库表2.1 先建立表结构(可以理解为表的列名,也就是字段名)在实际生产过程中,表结构是需要经过精心设计的。通用的语…

❤️1000道《计算机基础知识》汇总上----(建议收藏)❤️

1、 世界上首先实现存储程序的电子数字计算机是____。 A、ENIAC B、UNIVAC C、EDVAC D、EDSAC 2、计算机科学的奠基人是____。 A、查尔斯.巴贝奇 B、图灵 C、阿塔诺索夫 D、冯.诺依曼 3、 世界上首次提出存储程序计算机体系结构的是____。 A、艾仑•图灵 B、冯•诺…

HTML+CSS+JS实现 ❤️乐队成员图片展示ui特效❤️

效果演示: 代码目录: 主要代码实现: CSS样式: charset "utf-8"; /* CSS rest */body {font-size: 12px;font-family: "微软雅黑"; }* {margin: 0;padding: 0; }a {text-decoration: none; }ul, li, ol {list…

centos mysql 服务器_服务器数据库搭建流程(CentOs+mysql)

前言:服务器上数据库搭建需要知道Linux系统的版本,以前的Ubuntu14.04直接在终端下输入apt-get install (package)便可方便的下载并安装mysql,但是在centOs上就是行不通的,需要复杂的配置,不过在centOs里可以使用yum in…

HTML+CSS+JS实现 ❤️电商商品图片幻灯片特效❤️

效果演示: 代码目录: 主要代码实现: CSS样式: *, *::after, *::before {box-sizing: border-box; }html {background: #fff; }body {--color-text: #000;--color-bg: #fff;--color-link: #000;--color-link-hover: #858585;--col…

HTML+CSS+JS实现 ❤️响应式团队❤️

效果演示: 代码目录: 主要代码实现: CSS样式: body {margin: 0;min-height: 100vh;display: flex;justify-content: center;align-items: center;background-color: #f7f7f7; }.section-heading {font-family: "Dancing Scr…

canal mysql5.6_超详细的Canal入门,看这篇就够了!

思维导图文章已收录Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary前言我们都知道一个系统最重要的是数据,数据是保存在数据库里。但是很多时候不单止要保存在数据库中,还要同步保存到Elastic Search、HBase、…

HTML+CSS+JS实现React简单的计算器实例

效果演示:文末获取源码 代码目录: 主要代码实现: CSS样式: :root {/* color palette :: https://coolors.co/app/d63c6b-5cc8ff-efefef-292f36-d6d6d6 */--white: #efefef;--white-alpha: rgba(239, 239, 239, .64);--grey: #d6d…

HTML+CSS+JS实现 ❤️六边形圆柱弹性动画特效❤️

效果演示: 代码目录: 主要代码实现: 部分CSS样式: :root {--w: 8vmin;/*** change width ***/--h: 15vmin;/*** change height ***/--m: 8vmin;/*** change margin ***/--s: 1.25s;/*** change speed ***/ }body {margin: 0;…

shell 写入文件_phpMyAdmin利用日志文件GetSHELL

phpMyAdmin简介phpMyAdmin 是众多MySQL图形化管理工具中使用最为广泛的一种,是一款使用PHP 开发的基于B/S模式的MySQL客户端软件,该工具是基于 Web 跨平台的管理程序,并且支持简体中文,用户可以在官网上下载最新版本的。GetSHELL前…

HTML+CSS+JS实现 ❤️酷炫彩虹旋转隧道特效❤️

效果演示: 代码目录: 主要代码实现: 部分CSS样式: #c {position: absolute;top: calc(50vh - 200px);left: calc(50vw - 200px);}#alpha {position: absolute;top: calc(50vh 220px);left: calc(50vw - 50px);width: 100px;hei…

informix和mysql的区别_DB2与Informix区别比较

DB2与Informix比较特性 DB2 Informix开放性/可移植性 IBMDB2UDB在各层面,从网络协议的支持到应用开发程序的编程接口,数据库存储程序及触发器,服务器之间的分布式运作,都是基于最新的国际标准,以确保其开放性及移植性。…

HTML+CSS+JS实现 ❤️照相机快门图片动画特效❤️

效果演示: 代码目录: 主要代码实现: 部分CSS样式: html {height: 100%;overflow: hidden; }body {min-height: 100%; }.container {cursor: pointer;background-position: center center;background-size: cover;background-im…

往map里的vector添加_面试官问我同步容器(如Vector)的所有操作一定是线程安全的吗?我懵了!...

为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器、并发容器、阻塞队列等。最常见的同步容器就是Vector和Hashtable了,那么,同步容器的所有操作都是线程安全的吗?这个问…

HTML+CSS+JS实现 ❤️3D方块弹跳动画特效❤️

效果演示: 代码目录: 主要代码实现: 部分CSS样式: *, *::before, *::after {padding: 0;margin: 0 auto;box-sizing: border-box;transform-style: preserve-3d; }body {background-color: black;min-height: 100vh;display: f…