原本自动生成的manifest,未指定Application、启动activity:

<?xml version="1.0" encoding="utf-8"?>

独立调试、集成调试 ,分别使用“assembleDebug”构建结果如下:

3.2 多工程方案

3.2.1 方案概述

多工程方案,业务组件以library module形式存在于独立的工程。独立工程 自然就可以独立调试了,不再需要进行上面那些配置了。

例如,购物车组件 就是 新建的工程Cart 的 module_cart模块,业务代码就写在module_cart中即可。app模块是依赖module_cart。app模块只是一个组件的入口,或者是一些demo测试代码。 那么当所有业务组件都拆分成独立组件时,原本的工程就变成一个只有app模块的壳工程了,壳工程就是用来集成所有业务组件的。

3.2.1 maven引用组件

那么如何进行集成调试呢?使用maven引用组件:1、发布组件的arr包 到公司的maven仓库,2、然后在壳工程中就使用implemention依赖就可以了,和使用第三方库一毛一样。另外arr包 分为 快照版本(SNAPSHOT) 和 正(Realease)式版本,快照版本是开发阶段调试使用,正式版本是正式发版使用。具体如下:

首先,在module_cart模块中新建maven_push.gradle文件,和build.gradle同级目录

apply plugin: ‘maven’

configurations {
deployerJars
}

repositories {
mavenCentral()
}

//上传到Maven仓库的task
uploadArchives {
repositories {
mavenDeployer {
pom.version = ‘1.0.0’ // 版本号
pom.artifactId = ‘cart’ // 项目名称(通常为类库模块名称,也可以任意)
pom.groupId = ‘com.hfy.cart’ // 唯一标识(通常为模块包名,也可以任意)

//指定快照版本 maven仓库url, todo 请改为自己的maven服务器地址、账号密码
snapshotRepository(url: ‘http://xxx/maven-snapshots/’) {
authentication(userName: ‘***’, password: ‘***’)
}
//指定正式版本 maven仓库url, todo 请改为自己的maven服务器地址、账号密码
repository(url: ‘http://xxx/maven-releases/’) {
authentication(userName: ‘***’, password: ‘***’)
}
}
}
}

// type显示指定任务类型或任务, 这里指定要执行Javadoc这个task,这个task在gradle中已经定义
task androidJavadocs(type: Javadoc) {
// 设置源码所在的位置
source = android.sourceSets.main.java.sourceFiles
}

// 生成javadoc.jar
task androidJavadocsJar(type: Jar) {
// 指定文档名称
classifier = ‘javadoc’
from androidJavadocs.destinationDir
}

// 打包main目录下代码和资源的task,生成sources.jar
task androidSourcesJar(type: Jar) {
classifier = ‘sources’
from android.sourceSets.main.java.sourceFiles
}

//配置需要上传到maven仓库的文件
artifacts {
archives androidSourcesJar
archives androidJavadocsJar
}

maven_push.gradle主要就是发布组件ARR的配置:ARR的版本号、名称、maven仓地址账号等。

然后,再build.gradle中引用:

//build.gradle
apply from: ‘maven_push.gradle’

接着,点击Sync后,点击Gradle任务uploadArchives,即可打包并发布arr到maven仓。

最后,壳工程要引用组件ARR,需要先在壳工程的根目录下build.gradle中添加maven仓库地址:

allprojects {
repositories {
google()
jcenter()
//私有服务器仓库地址
maven {
url ‘http://xxx’
}
}
}

接着在app的build.gradle中添加依赖即可:

dependencies {

implementation ‘com.hfy.cart:cart:1.0.0’
//以及其他业务组件
}

可见,多工程方案 和我们平时使用第三方库是一样的,只是我们把组件ARR发布到公司的私有maven仓而已。

实际上,我个人比较建议 使用多工程方案的。

  • 单工程方案没法做到代码权限管控,也不能做到开发人员职责划分明确,每个开发人员都可以对任意的组件进行修改,显然还是会造成混乱。
  • 多工程把每个组件都分割成单独的工程,代码权限可以明确管控。集成测试时,通过maven引用来集成即可。并且业务组件和业务基础组件也可以 和 基础组件一样,可以给公司其他项目复用。

注意,我在Demo里 使用的是多工程方案,并且是 把ARR发到JitPack仓,这样是为了演示方便,和发到公司私有maven仓是一个意思。 1、需要根目录下build.gradle中添加JitPack仓地址:maven { url ‘jitpack.io’ } ; 2、JitPack是自定义的Maven仓库,不过它的流程极度简化,只需要输入Github项目地址就可发布项目。

四、页面跳转

4.1 方案—ARouter

前面说到,组件化的核心就是解耦,所以组件间是不能有依赖的,那么如何实现组件间的页面跳转呢?

例如 在首页模块 点击 购物车按钮 需要跳转到 购物车模块的购物车页面,两个模块之间没有依赖,也就说不能直接使用 显示启动 来打开购物车Activity,那么隐式启动呢? 隐式启动是可以实现跳转的,但是隐式 Intent 需要通过 AndroidManifest 配置和管理,协作开发显得比较麻烦。这里我们采用业界通用的方式—路由

比较著名的路由框架 有阿里的ARouter、美团的WMRouter,它们原理基本是一致的。

这里我们采用使用更广泛的ARouter:“一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦”。

4.2 ARouter实现路由跳转

前面提到,所有的业务组件都依赖了 Common 组件,所以我们在 Common 组件中使用关键字**“api”**添加的依赖,业务组件都能访问。 我们要使用 ARouter 进行界面跳转,需要Common 组件添加 Arouter 的依赖(另外,其它组件共同依赖的库也要都放到 Common 中统一依赖)。

4.2.1 引入依赖

因为ARouter比较特殊,“arouter-compiler ” 的annotationProcessor依赖 需要所有使用到 ARouter 的组件中都单独添加,不然无法在 apt 中生成索引文件,就无法跳转成功。并且在每个使用到 ARouter 的组件的 build.gradle 文件中,其 android{} 中的 javaCompileOptions 中也需要添加特定配置。然后壳工程需要依赖业务组件。如下所示:

//common组件的build.gradle
dependencies {

api ‘com.alibaba:arouter-api:1.4.0’
annotationProcessor ‘com.alibaba:arouter-compiler:1.2.1’
//业务组件、业务基础组件 共同依赖的库(网络库、图片库等)都写在这里~
}

//业务组件的build.gradle
android {

defaultConfig {

javaCompileOptions {
annotationProcessorOptions {
arguments = [AROUTER_MODULE_NAME: project.getName()]
}
}
}

}
dependencies {

annotationProcessor ‘com.alibaba:arouter-compiler:1.2.1’
implementation ‘com.github.hufeiyang:Common:1.0.0’//业务组件依赖common组件
}

//壳工程app module的build.gradle
dependencies {

//这里没有使用私有maven仓,而是发到JitPack仓,一样的意思~
// implementation ‘com.hfy.cart:cart:1.0.0’
implementation ‘com.github.hufeiyang:Cart:1.0.1’ //依赖购物车组件
implementation ‘com.github.hufeiyang:HomePage:1.0.2’ //依赖首页组件

//壳工程内 也需要依赖Common组件,因为需要初始化ARouter
implementation ‘com.github.hufeiyang:Common:1.0.0’
}

4.2.2 初始化

依赖完了,先要对ARouter初始化,需要在Application内完成:

public class MyApplication extends Application {

@Override
public void onCreate() {
super.onCreate();

// 这两行必须写在init之前,否则这些配置在init过程中将无效
if (BuildConfig.DEBUG) {
// 打印日志
ARouter.openLog();
// 开启调试模式(如果在InstantRun模式下运行,必须开启调试模式!线上版本需要关闭,否则有安全风险)
ARouter.openDebug();
}
// 尽可能早,推荐在Application中初始化
ARouter.init(this);
}
}

4.2.3 路由跳转

好了,准备工作都完成了。并且知道 首页组件是没有依赖购物车组件的,下面就来实现前面提到的 首页组件 无依赖 跳转到 购物车组件页面

而使用ARouter进行简单路由跳转,只有两步:添加注解路径、通过路径路由跳转。

1、在支持路由的页面上添加注解@Route(path = “/xx/xx”),路径需要注意的是至少需要有两级,/xx/xx。这里就是购物车组件的CartActivity:

@Route(path = “/cart/cartActivity”)
public class CartActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
}
}

2、然后在首页组件的HomeActivity 发起路由操作—点击按钮跳转到购物车,调用ARouter.getInstance().build("/xx/xx").navigation()即可:

@Route(path = “/homepage/homeActivity”)
public class HomeActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);

findViewById(R.id.btn_go_cart).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//通过路由跳转到 购物车组件的购物车页面(但没有依赖购物车组件)
ARouter.getInstance()
.build("/cart/cartActivity")
.withString(“key1”,“value1”)//携带参数1
.withString(“key2”,“value2”)//携带参数2
.navigation();
}
});
}
}

另外,注意在HomeActivity上添加了注解和路径,这是为了壳工程的启动页中直接打开首页。还看到路由跳转可以像startActivity一样待参数。

最后,壳工程的启动页中 通过路由打开首页(当然这里也可以用startActivity(),毕竟壳工程依赖了首页组件):

//启动页
public class SplashActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//通过路由直接打开home组件的HomeActivity,
ARouter.getInstance().build("/homepage/homeActivity").navigation();
finish();
}
}

我们run壳工程 最后看下效果: 到这里,组件间页面跳转的问题也解决了。

五、组件间通信

组件间没有依赖,又如何进行通信呢?

例如,首页需要展示购物车中商品的数量,而查询购物车中商品数量 这个能力是购物车组件内部的,这咋办呢?

5.1 服务暴露组件

平时开发中 我们常用 接口 进行解耦,对接口的实现不用关心,避免接口调用与业务逻辑实现紧密关联。这里组件间的解耦也是相同的思路,仅依赖和调用服务接口,不会依赖接口的实现。

可能你会有疑问了:既然首页组件可以访问购物车组件接口了,那就需要依赖购物车组件啊,这俩组件还是耦合了啊,那咋办啊?答案是组件拆分出可暴露服务。见下图: 左侧是组件间可以调用对方服务 但是有依赖耦合。右侧,发现多了export_homeexport_cart,这是对应拆分出来的专门用于提供服务的暴露组件。操作说明如下:

  • 暴露组件 只存放 服务接口、服务接口相关的实体类、路由信息、便于服务调用的util等
  • 服务调用方 只依赖 服务提供方的 露组件,如module_home依赖export_cart,而不依赖module_cart
  • 组件 需要依赖 自己的暴露组件,并实现服务接口,如module_cart依赖export_cart 并实现其中的服务接口
  • 接口的实现注入 依然是由ARouter完成,和页面跳转一样使用路由信息

下面按照此方案 来实施 首页调用购物车服务 来获取商品数量,更好地说明和理解。

5.2 实施

5.2.1 新建export_cart

首先,在购物车工程中新建module即export_cart,在其中新建接口类ICartService并定义获取购物车商品数量方法,注意接口必须继承IProvider,是为了使用ARouter的实现注入:

/**

  • 购物车组件对外暴露的服务
  • 必须继承IProvider
  • @author hufeiyang
    */
    public interface ICartService extends IProvider {

/**

  • 获取购物车中商品数量
  • @return
    */
    CartInfo getProductCountInCart();
    }

CartInfo是购物车信息,包含商品数量:

/**

  • 购物车信息

  • @author hufeiyang
    */
    public class CartInfo {

/**

  • 商品数量
    */
    public int productCount;
    }

接着,创建路由表信息,存放购物车组件对外提供跳转的页面、服务的路由地址:

/**

  • 购物车组件路由表
  • 即 购物车组件中 所有可以从外部跳转的页面 的路由信息
  • @author hufeiyang
    */
    public interface CartRouterTable {

/**

  • 购物车页面
    */
    String PATH_PAGE_CART = “/cart/cartActivity”;

/**

  • 购物车服务
    */
    String PATH_SERVICE_CART = “/cart/service”;

}

前面说页面跳转时是直接使用 路径字符串 进行路由跳转,这里是和服务路由都放在这里统一管理。

然后,为了外部组件使用方便新建CartServiceUtil:

/**

  • 购物车组件服务工具类
  • 其他组件直接使用此类即可:页面跳转、获取服务。
  • @author hufeiyang
    */
    public class CartServiceUtil {

/**

  • 跳转到购物车页面
  • @param param1
  • @param param2
    */
    public static void navigateCartPage(String param1, String param2){
    ARouter.getInstance()
    .build(CartRouterTable.PATH_PAGE_CART)
    .withString(“key1”,param1)
    .withString(“key2”,param2)
    .navigation();
    }

/**

  • 获取服务
  • @return
    */
    public static ICartService getService(){
    //return ARouter.getInstance().navigation(ICartService.class);//如果只有一个实现,这种方式也可以
    return (ICartService) ARouter.getInstance().build(CartRouterTable.PATH_SERVICE_CART).navigation();
    }

/**

  • 获取购物车中商品数量
  • @return
    */
    public static CartInfo getCartProductCount(){
    return getService().getProductCountInCart();
    }
    }

注意到,这里使用静态方法 分别提供了页面跳转、服务获取、服务具体方法获取。 其中服务获取 和页面跳转 同样是使用路由,并且服务接口实现类 也是需要添加@Route注解指定路径的。

到这里,export_cart就已经准备完毕,我们同样发布一个export_cart的ARR(“com.github.hufeiyang.Cart:export_cart:xxx”)。

再来看看module_cart对服务接口的实现。

5.2.2 module_cart的实现

首先,module_cart需要依赖export_cart:

//module_cart的Build.gradle
dependencies {

annotationProcessor ‘com.alibaba:arouter-compiler:1.2.1’
implementation ‘com.github.hufeiyang:Common:1.0.0’

//依赖export_cart
implementation ‘com.github.hufeiyang.Cart:export_cart:1.0.5’
}

点击sync后,接着CartActivity的path改为路由表提供:

@Route(path = CartRouterTable.PATH_PAGE_CART)
public class CartActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_cart);
}
}

然后,新建服务接口的实现类来实现ICartService,添加@Route注解指定CartRouterTable中定义的服务路由

/**

  • 购物车组件服务的实现
  • 需要@Route注解、指定CartRouterTable中定义的服务路由
  • @author hufeiyang
    */
    @Route(path = CartRouterTable.PATH_SERVICE_CART)
    public class CartServiceImpl implements ICartService {

@Override
public CartInfo getProductCountInCart() {
//这里实际项目中 应该是 请求接口 或查询数据库
CartInfo cartInfo = new CartInfo();
cartInfo.productCount = 666;
return cartInfo;
}

@Override
public void init(Context context) {
//初始化工作,服务注入时会调用,可忽略
}
}

这里的实现是直接实例化了CartInfo,数量赋值666。然后发布一个ARR(“com.github.hufeiyang.Cart:module_cart:xxx”)。

5.2.3 module_home中的使用和调试

module_home需要依赖export_cart:

//module_home的Build.gradle
dependencies {

annotationProcessor ‘com.alibaba:arouter-compiler:1.2.1’
implementation ‘com.github.hufeiyang:Common:1.0.0’

//注意这里只依赖export_cart(module_cart由壳工程引入)
implementation ‘com.github.hufeiyang.Cart:export_cart:1.0.5’
}

在HomeActivity中新增TextView,调用CartServiceUtil获取并展示购物车商品数量:

@Route(path = “/homepage/homeActivity”)
public class HomeActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);

//跳转到购物车页面
findViewById(R.id.btn_go_cart).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//通过路由跳转到 购物车组件的购物车页面(但没有依赖购物车组件)
// ARouter.getInstance()
// .build("/cart/cartActivity")
// .withString(“key1”,“param1”)//携带参数1
// .withString(“key2”,“param2”)//携带参数2
// .navigation();

CartServiceUtil.navigateCartPage(“param1”, “param1”);
}
});

//调用购物车组件服务:获取购物车商品数量
TextView tvCartProductCount = findViewById(R.id.tv_cart_product_count);
tvCartProductCount.setText(“购物车商品数量:”+ CartServiceUtil.getCartProductCount().productCount);
}
}

看到 使用CartServiceUtil.getCartProductCount()获取购物车信息并展示,跳转页面也改为了CartServiceUtil.navigateCartPage()方法。

到这里home组件的就可以独立调试了:页面跳转和服务调用,独立调试ok后 再集成到壳工程。 先让HomePage工程的app模块依赖Common组件、module_cart 以及本地的module_home

//HomePage工程,app模块的Build.gradle
dependencies {

//引入本地Common组件、module_cart、module_home,在app module中独立调试使用
implementation ‘com.github.hufeiyang:Common:1.0.0’
implementation ‘com.github.hufeiyang.Cart:module_cart:1.0.6’

implementation project(path: ‘:module_home’)
}

然后新建MyApplication初始化ARouter、在app的MainActivity中使用ARouter.getInstance().build("/homepage/homeActivity").navigation()打开首页,这样就可以调试了。

调试ok后接着就是集成到壳工程。

5.2.4 集成到壳工程

壳工程中的操作和独立调试类似,区别是对首页组件引入的是ARR:

dependencies {

//这里没有使用私有maven仓,而是发到JitPack仓,一样的意思~
// implementation ‘com.hfy.cart:cart:1.0.0’
implementation ‘com.github.hufeiyang.Cart:module_cart:1.0.6’
implementation ‘com.github.hufeiyang:HomePage:1.0.4’

//壳工程内 也需要依赖Common组件,因为需要初始化ARouter
implementation ‘com.github.hufeiyang:Common:1.0.0’
}

最后run壳工程来看下效果: 获取数量是666、跳转页面成功。

另外,除了export_xxx这种方式,还可以添加一个 ComponentBase 组件,这个组件被所有的Common组件依赖,在这个组件中分别添加定义了业务组件可以对外提供访问自身数据的抽象方法的 Service。相当于把各业务组件的export整合到ComponentBase中,这样就只添加了一个组件而已。但是这样就不好管理了,每个组件对外能力的变更都要改ComponentBase。

另外,除了组件间方法调用,使用EventBus在组件间传递信息也是ok的(注意Event实体类要定义在export_xxx中)。

好了,到这里组件间通信问题也解决了。

六、fragment实例获取

上面介绍了Activity 的跳转,我们也会经常使用 Fragment。例如常见的应用主页HomeActivity 中包含了多个属于不同组件的 Fragment、或者有一个Fragment多个组件都需要用到。通常我们直接访问具体 Fragment 类来new一个Fragment 实例,但这里组件间没有直接依赖,那咋办呢?答案依然是ARouter

先在module_cart中创建CartFragment:

//添加注解@Route,指定路径
@Route(path = CartRouterTable.PATH_FRAGMENT_CART)
public class CartFragment extends Fragment {

public CartFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//显示“cart_fragment"
return inflater.inflate(R.layout.fragment_cart, container, false);
}
}

同时是fragment添加注解@Route,指定路由路径,路由还是定义在export_cart的CartRouterTable中,所以export_cart需要先发一个ARR,module_cart来依赖,然后module_cart发布ARR。

然后再module_home中依赖export_cart,使用ARouter获取Fragment实例:

@Route(path = “/homepage/homeActivity”)
public class HomeActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);

FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction= manager.beginTransaction();

//使用ARouter获取Fragment实例 并添加
Fragment userFragment = (Fragment) ARouter.getInstance().build(CartRouterTable.PATH

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

_FRAGMENT_CART).navigation();
transaction.add(R.id.fl_test_fragment, userFragment, “tag”);
transaction.commit();
}
}

可以先独立调试,然后集成到壳工程——依赖最新的module_cart 、HomePage,结果如下:

绿色部分就是引用自cart组件的fragment。

七、Application生命周期分发

我们通常会在Application的onCreate中做一些初始化任务,例如前面提到的ARouter初始化。而业务组件有时也需要获取应用的Application,也要在应用启动时进行一些初始化任务。

你可能会说,直接在壳工程Application的onCreate操作就可以啊。但是这样做会带来问题:因为我们希望壳工程和业务组件 代码隔离(虽然有依赖),并且 我们希望组件内部的任务要在业务组件内部完成。

那么如何做到 各业务组件 无侵入地获取 Application生命周期 呢?——答案是 使用AppLifeCycle插件,它专门用于在Android组件化开发中,Application生命周期主动分发到组件。具体使用如下:

  1. common组件依赖 applifecycle-api

首先,common组件通过 api 添加 applifecycle-api 依赖 并发布ARR:

//common组件 build.gradle
dependencies {

//AppLifecycle
api ‘com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-api:1.0.4’
}

  1. 业务组件依赖applifecycle-compiler、实现接口+注解

各业务组件都要 依赖最新common组件,并添加 applifecycle-compiler 的依赖:

//业务组件 build.gradle

//这里Common:1.0.2内依赖了applifecycle-api
implementation ‘com.github.hufeiyang:Common:1.0.2’
annotationProcessor ‘com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-compiler:1.0.4’

sync后,新建类来实现接口IApplicationLifecycleCallbacks用于接收Application生命周期,且添加@AppLifecycle注解。

例如 Cart组件的实现:

/**

  • 组件的AppLifecycle
  • 1、@AppLifecycle
  • 2、实现IApplicationLifecycleCallbacks
  • @author hufeiyang
    */
    @AppLifecycle
    public class CartApplication implements IApplicationLifecycleCallbacks {

public Context context;

/**

  • 用于设置优先级,即多个组件onCreate方法调用的优先顺序
  • @return
    */
    @Override
    public int getPriority() {
    return NORM_PRIORITY;
    }

@Override
public void onCreate(Context context) {
//可在此处做初始化任务,相当于Application的onCreate方法
this.context = context;

Log.i(“CartApplication”, “onCreate”);
}

@Override
public void onTerminate() {
}

@Override
public void onLowMemory() {
}

@Override
public void onTrimMemory(int level) {
}
}

实现的方法 有onCreate、onTerminate、onLowMemory、onTrimMemory。最重要的就是onCreate方法了,相当于Application的onCreate方法,可在此处做初始化任务。 并且还可以通过getPriority()方法设置回调 多个组件onCreate方法调用的优先顺序,无特殊要求设置NORM_PRIORITY即可。

  1. 壳工程引入AppLifecycle插件、触发回调

壳工程引入新的common组件、业务组件,以及 引入AppLifecycle插件:

//壳工程根目录的 build.gradle

buildscript {

repositories {
google()
jcenter()

//applifecycle插件仓也是jitpack
maven { url ‘https://jitpack.io’ }
}
dependencies {
classpath ‘com.android.tools.build:gradle:3.6.1’

//加载插件applifecycle
classpath ‘com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-plugin:1.0.3’
}
}

//app module 的build.gradle

apply plugin: ‘com.android.application’
//使用插件applifecycle
apply plugin: ‘com.hm.plugin.lifecycle’

dependencies {

//这里没有使用私有maven仓,而是发到JitPack仓,一样的意思~
// implementation ‘com.hfy.cart:cart:1.0.0’
implementation ‘com.github.hufeiyang.Cart:module_cart:1.0.11’
件onCreate方法调用的优先顺序,无特殊要求设置NORM_PRIORITY即可。

  1. 壳工程引入AppLifecycle插件、触发回调

壳工程引入新的common组件、业务组件,以及 引入AppLifecycle插件:

//壳工程根目录的 build.gradle

buildscript {

repositories {
google()
jcenter()

//applifecycle插件仓也是jitpack
maven { url ‘https://jitpack.io’ }
}
dependencies {
classpath ‘com.android.tools.build:gradle:3.6.1’

//加载插件applifecycle
classpath ‘com.github.hufeiyang.Android-AppLifecycleMgr:applifecycle-plugin:1.0.3’
}
}

//app module 的build.gradle

apply plugin: ‘com.android.application’
//使用插件applifecycle
apply plugin: ‘com.hm.plugin.lifecycle’

dependencies {

//这里没有使用私有maven仓,而是发到JitPack仓,一样的意思~
// implementation ‘com.hfy.cart:cart:1.0.0’
implementation ‘com.github.hufeiyang.Cart:module_cart:1.0.11’

“终于懂了” 系列,安卓工程师的面试题相关推荐

  1. “终于懂了” 系列:Android屏幕刷新机制—VSync、Choreographer 全面理解!

    文章目录 一.背景和疑问 二.显示系统基础知识 2.1 基础概念 2.2 双缓存 2.2.1 画面撕裂 原因 2.2.2 双缓存 2.2.3 VSync 三.Android屏幕刷新机制 3.1 And ...

  2. 9年前,字节跳动第一个安卓工程师是这样工作的

    从2012到2021,今天的字节跳动已经走过了9周年,员工人数也已经突破了10W. 不过,回想九年前的创业早期,整个公司只有十几个人,探索方向期间,创始团队一口气做了包括今日头条在内的12款App,但 ...

  3. 安卓工程师教你玩转Android

    查看书籍详细信息: 安卓工程师教你玩转Android 编辑推荐 让你的手机真的变成"战斗机"! 由浅入深,满足多种需求 授人以鱼,更授人以渔 知其然,更知其所以然 紧跟Androi ...

  4. 长沙android工程师,长沙安卓工程师辅导

    长沙安卓工程师辅导?安卓开发在现在是非常的火热,不管是自己爱好学习,还是找工作,安卓开发都是非常的,而且安卓应用的趋势也越来越火.所以小编作为一个开发者,说下怎样学习安卓开发. 如何学好安卓? 明智地 ...

  5. 鸿蒙操作是基于安卓,华为鸿蒙系统终于发布,与安卓有何区别?随时可以应用在手机上...

    原标题:华为鸿蒙系统终于发布,与安卓有何区别?随时可以应用在手机上 华为研发新的操作平台鸿蒙OS的消息一经推出就备受关注,本以为鸿蒙OS是一款全新手机操作系统,随后发现它并不只是手机操作系统,它是物联 ...

  6. 五险一金,终于懂了!

    五险一金,终于懂了!   养老保险:  一般要交满15年,到退休的时候才能终生享受养老金,所以想拿养老金的人请务必在自己退休前15年就开始交.如果到退休年龄交养老保险不满15年,那等到你退休的时候国家 ...

  7. 一文彻底搞懂Mybatis系列(十六)之MyBatis集成EhCache

    MyBatis集成EhCache 一.MyBatis集成EhCache 1.引入mybatis整合ehcache的依赖 2.类根路径下新建ehcache.xml,并配置 3.POJO类 Clazz 4 ...

  8. 服务器显示器无信号,终于懂了显示器无信号输出怎么解决?

    终于懂了显示器无信号输出怎么解决? 日期:2019-11-07 17:09:28 浏览:49 核心提示:显示器无信号输出怎么解决?电脑在开机后显示器通电但是没有信号输出,通常这种情况都是由于信号线或主 ...

  9. 转载---终于懂了通信这个行业,我却已经离开!

    转载链接: http://m.elecfans.com/article/521773.html 仅作个人记录阅读使用 离开通信行业已经有一段日子了.换了行业之后,慢慢的淡忘了通信的各种艰辛和酸甜苦辣. ...

  10. 安卓工程师跳槽面试全指南

    课程介绍 年关将至,不少人出于职业规划的考虑,会开始出现跳槽的想法.跳槽念头一旦产生,所有的咨询都不过是为了"说服自己"而已.于是,我们要关注的重点就变成"怎么跳得更好? ...

最新文章

  1. 使用hibernate与mysql时数据不能插入的原因及解决办法
  2. Apache commons-io
  3. 【深度学习入门到精通系列】什么是消融实验(Ablation experiment)
  4. ADMM:交替方向乘子算法
  5. 中文站最好的WordPress主题推荐
  6. Python基础知识 D9
  7. php redis 队列抢红包_redis 队列操作的例子(php)
  8. Kafka架构及基本原理简析
  9. Windows10下设置开机自启动自己的程序
  10. php做个抽签人名,怎样在excel制作一个用于抽签函数,别的工具也行(excel随机抽取人名不重复)...
  11. 计算机学报英语,修改稿要求-计算机学报.PDF
  12. 计算机无法进去系统,开机进入bios无法进入系统怎么办_电脑开机就进入bios的解决方法...
  13. ***测试技巧总结更新篇2
  14. python发明小故事简写_科学发明小故事20字
  15. ResNet详解:ResNet到底在解决什么问题?
  16. 面试高级算法梳理笔记
  17. spring-kuang
  18. java不区分大小写查找字符串
  19. 浪潮超融合服务器虚拟机管理,浪潮联合VMware发布新一代超融合一体机,十倍提速数据中心部署效率...
  20. PESD5V0F1BSF特性好处

热门文章

  1. 最新Via轻插件下载
  2. DeepFool: a simple and accurate method to fool deep neural networks
  3. GAN的一些经典网络的基本思想
  4. 26 王者荣耀刷金币脚本
  5. OutMan——C语言中字符串处理函数、内存管理和内存分区
  6. 简述使用configurations.all统一androidx的版本
  7. cdr 表格自动填充文字_【Excel技巧】excel单元格自动填充英文字母编号
  8. js实现页面的多个日期时间倒计时效果(多个拼团)
  9. 2019年个人所得税计算机模板,2019年最新个税计算Excel模版,人手一份!
  10. CC2640R2F学习笔记(2)——OLED屏使用