Android Gradle学习(六):NamedDomainObjectContainer详解

第一次看到 NamedDomainObjectContainer 的时候,让我迷惑了好一阵子,这到底是个什么玩意?现在让我们来揭开它神秘的面纱,看看它到底是什么,有什么作用。

1. NamedDomainObjectContainer的使用场景

前面在讲解 Gradle Extension 的时候,说到名为 android 的 Extension 是由 BaseExtension 这个类来实现的,里面对 buildTypes 是这样定义的:

private final NamedDomainObjectContainer<BuildType> buildTypes;

buildTypes 就是 NamedDomainObjectContainer 类型的,先来看看 buildTypes 在 Android 中是怎么使用的,下面这段代码应该都很熟悉了,它定义了 debug、relase 两种打包模式:

android {

    buildTypes {
        release {
            // 是否开启混淆
            minifyEnabled true
            // 开启ZipAlign优化
            zipAlignEnabled true
            //去掉不用资源
            shrinkResources true
            // 混淆文件位置
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            // 使用release签名
            signingConfig signingConfigs.hmiou
        }

        debug {
            signingConfig signingConfigs.hmiou
        }
    }
}

当我们新建一个项目的时候,默认会有 debug、release 这2个配置,那么问题来了:debug、release 能不能修改为其他名字?能不能增加其他的名字来配置,比方说我想增加一个测试包配置 test ?还有就是 release 里面都能配置哪些属性呢?

我来说下结果,如果不确定的,可以实际验证一下:

  1. debug、release 是可以修改成其他名字的,你可以替换成你喜欢的名字;
  2. 你可以增加任意不同名字的配置,比如增加一个开发版本的打包配置 dev ;
  3. 可配置的属性可参考接口:com.android.builder.model.BuildType ;

可以看到它是非常灵活的,你可以根据不同的场景定义不同的配置,每个不同的命名空间都会生成一个 BuildType 配置。要实现这样的功能,必须使用 NamedDomainObjectContainer 类型。

2. NamedDomainObjectContainer是什么

顾名思义就是命名领域对象容器,它的主要功能有:

  • 它能够通过DSL(在Gradle脚本中)创建指定 type 的对象实例;
  • 指定的 type 必须有一个 public 构造函数,且必须带有一个 String name 的参数,type 类型的领域对象必须有名为“name”的属性;
  • 它是一个实现了 SortedSet 接口的容器,所以所有领域对象的 name 属性值都必须是唯一的,在容器内部会用 name 属性来排序;

来看看官方文档里的说明:

A named domain object container is a specialisation of NamedDomainObjectSet that adds the ability to create instances of the element type.

Note that a container is an implementation of SortedSet, which means that the container is guaranteed to only contain elements with unique names within this container. Furthermore, items are ordered by their name.

3. 怎么创建NamedDomainObjectContainer

NamedDomainObjectContainer 需要通过 Project.container(...) API 来创建,其定义为:

<T> NamedDomainObjectContainer<T> container(Class<T> type)
<T> NamedDomainObjectContainer<T> container(Class<T> type, NamedDomainObjectFactory<T> factory)
<T> NamedDomainObjectContainer<T> container(java.lang.Class<T> type, Closure factoryClosure

来看个具体的实例:

//这是领域对象类型定义
class TestDomainObj {
    
    //必须定义一个 name 属性,并且这个属性值初始化以后不要修改
    String name

    String msg

    //构造函数必须有一个 name 参数
    public TestDomainObj(String name) {
        this.name = name
    }

    void msg(String msg) {
        this.msg = msg
    }

    String toString() {
        return "name = ${name}, msg = ${msg}"
    }
}

//创建一个扩展
class TestExtension {

    //定义一个 NamedDomainObjectContainer 属性
    NamedDomainObjectContainer<TestDomainObj> testDomains

    public TestExtension(Project project) {
        //通过 project.container(...) 方法创建 NamedDomainObjectContainer 
        NamedDomainObjectContainer<TestDomainObj> domainObjs = project.container(TestDomainObj)
        testDomains = domainObjs
    }

    //让其支持 Gradle DSL 语法
    void testDomain(Action<NamedDomainObjectContainer<TestDomainObj>> action) {
        action.execute(testDomains)
    }

    void test() {
        //遍历命名领域对象容器,打印出所有的领域对象值
        testDomains.all { data ->
            println data        
        }
    }
}

//创建一个名为 test 的 Extension
def testExt = getExtensions().create("test", TestExtension, project)

test {
    testDomain {
        domain2 {
            msg "This is domain2"
        }
        domain1 {
            msg "This is domain1"
        }
        domain3 {
            msg "This is domain3"
        }
    }   
}

task myTask << {
    testExt.test()
}

运行结果如下:

name = domain1, msg = This is domain1
name = domain2, msg = This is domain2
name = domain3, msg = This is domain3

4. 查找和遍历

NamedDomainObjectContainer 既然是一个容器类,与之相应的必然会有查找容器里的元素和遍历容器的方法:

//遍历
void all(Closure action)
//查找
<T> T getByName(String name)
//查找
<T> T findByName(String name)

还是接着前面的例子:

//通过名字查找
TestDomainObj testData = testDomains.getByName("domain2")
println "getByName: ${testData}"

//遍历命名领域对象容器,打印出所有的领域对象值
testDomains.all { data ->
    println data        
}                   

需要注意的是,Gradle 中有很多容器类的迭代遍历方法有 each(Closure action)、all(Closure action),但是一般我们都会用 all(...) 来进行容器的迭代。all(...) 迭代方法的特别之处是,不管是容器内已存在的元素,还是后续任何时刻加进去的元素,都会进行遍历。

系列文章

Android Gradle学习(一):Gradle基础入门
Android Gradle学习(二):如何创建Task
Android Gradle学习(三):Task进阶学习
Android Gradle学习(四):Project详解
Android Gradle学习(五):Extension详解
Android Gradle学习(六):NamedDomainObjectContainer详解
Android Gradle学习(七):Gradle构建生命周期
Android Gradle学习(八):统计Task执行时长
Android Gradle学习(九):一些有用的小技巧

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容