AndroidGradle权威指南笔记

第一章:准备

1.环境配置

(1)下载gradle-[version]-all.zip。
(2)配置环境变量。
(3)使用命令gradle -v检查安装是否成功。
(4)使用命令gradle -help查看帮助。

2.编写Hello World

(1)新建一个工程目录。
(2)新建一个build.gradle的文本文件。
(3)输入以下代码:

1
2
3
4
5
task hello {
doLast {
println 'Hello World!'
}
}

(4)工程目录下执行gradle hello

3.生成Wrapper

  • GradleWrapper是用于兼容不同gradle版本的“通用接口”。

  • 在根目录下执行gradle wrapper,将自动生成以下文件:
    gradlewrapper

  • 触类旁通,gradle wrapper命令其实是执行了一个名叫wrapper的task。

  • 我们可以重写该task,代码如下:

1
2
3
4
5
//修改gradle-wrapper.properties里的参数值
task wrapper(type : Wrapper) {
gradleVersion = '4.1'
...
}

4.开关级别

日志选项 意义
-q / –quiet 重要消息及以上
-i / –info info及以上
-d / –debug debug及以上
错误堆栈选项 意义
-s / –stacktrace 重要堆栈
-S / –full-stacktrace 全堆栈

5.常用辅助命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.查看帮助
./gradlew -help
2.查看Tasks
./gradlew tasks
3.强制刷新Maven库
./gradlew --refresh-dependencies assemble
4.多任务串行执行
./gradlew clean assembleDebug
5.命令缩写
./gradlew connectCheck 等价 ./gradlew cc

第二章:初识Groovy

Groovy是基于JVM的动态语言。它支持闭包,支持DSL,是一门灵活的动态脚步语言。

1.字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
task printStringVar << {
def name1 = '张三'
def name2 = "李四"
println '单引号 ${name1}'
println "双引号 ${name1}"
println '单引号 ${name2}'
println "双引号 ${name2}"
}
输入:./gradlew printStringVar
输出:
单引号 ${name1}
双引号 张三
单引号 ${name2}
双引号 李四

2.集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
1.List
task printList << {
def numList = [1, 2, 3, 4]
println numList.getClass().name
println numList[1]//访问第二个元素
println numList[-1]//访问倒数第一个元素
println numList[-2]//访问倒数第二个元素
println numList[1..3]//访问第二个到第四个元素
numList.each {
println it
}
}
输出:
java.util.ArrayList
2
4
3
[2, 3, 4]
1
2
3
4
2.Map
task printMap << {
def map = ['width':1024, 'height':720]
println map.getClass().name
println map['width']
println map.height
map.each {
println "Key:${it.key},Value:${it.value}"
}
}
输出:
java.util.LinkedHashMap
1024
720
Key:width,Value:1024
Key:height,Value:720

3.方法

  • 调用可以省略括号
1
2
3
4
5
6
7
8
task invokeMethod << {
method1(1, 2)
method1 1, 2
}
def method1 (int a,int b) {
println a + b
}
  • return可以不写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
task printMethodReturn << {
def max1 = method2 1, 2
def max2 = method2 6, 4
println "max1:${max1},max2:${max2}"
}
def method2 (int a, int b) {
if (a > b) {
a
} else {
b
}
}
输出:
max1:2,max2:6
  • JavaBean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
task helloJavaBean << {
Person p = new Person()
println "name:${p.name}"
p.name = "Tom"
println "name:${p.name}"
//能访问age是因为有get方法,但并不能修改age,因为没有set方法。
println "age:${p.age}"
}
class Person {
private String name
public int getAge() {
12
}
}
输出:
name:null
name:Tom
age:12
  • 闭包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//---------------------task 1---------------------
task helloClosure << {
customEach {//两个大括号之间就是闭包
println it
}
}
def customEach(closure) {
for(int i in 1..10) {
closure(i)
}
}
//---------------------task 2---------------------
task helloMap << {
eachMap {//两个大括号之间就是闭包
k, v ->
println "${k} , ${v}"
}
}
def eachMap(closure) {
def map = ["name":"abc","age":18]
map.each {
closure(it.key, it.value)//向闭包传递数据
}
}
//---------------------task 3---------------------
task configClosure << {
person {
name = "abc"
age = 20
dumpPerson()
}
}
class Person {
String name
int age
def dumpPerson() {
println "name is ${name},age is ${age}"
}
}
def person (Closure<Person> closure) {
Person p = new Person()
closure.delegate = p
closure.setResolveStrategy(Closure.DELEGATE_FIRST);
closure(p)
}

第三章:初识Gradle

1.settings文件

1
2
3
4
5
6
7
8
//settings.gradle
rootProject.name = 'XXX'
//与主module在同一个根目录下
include ':ModuleA'
//不与主module在同一个根目录下,自定义相对路径
include ':RxJava'
project(':RxJava').projectDir = new File(rootDir, 'joking/rxjava')

2.build.gradle文件

每个module都有一个build.gradle文件,而主module更可以配置子module属性或者全module属性。请记住,subprojects和allprojects是两个方法,接收闭包进行修改里面的参数,还可以执行其他命令。

1
2
3
4
5
6
7
8
9
10
11
subprojects {
repositories {
jcenter()
}
}
allprojects {
repositories {
jcenter()
}
}

3.Projects和Tasks

一个Project包含许多个Tasks。Task是一个原子性操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
task customTask1 {
doFirst {
println 'customTask1:doFirst'
}
doLast {
println 'customTask1:doLast'
}
}
//原型,两者作用一样。
tasks.create("customTask2") {
doFirst {
println 'customTask2:doFirst'
}
doLast {
println 'customTask2:doLast'
}
}

4.任务依赖

有时候我们要求作为前提条件的任务完成了才能执行当前任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
task hello << {
println 'hello'
}
task world << {
println 'world'
}
//1.单依赖
task main(dependsOn:hello) {
doLast {
println 'main'
}
}
输出结果:
> Task :hello
hello
> Task :main
main
//2.多依赖
task main2 {
dependsOn hello,world
doLast {
println 'main'
}
}
输出结果:
> Task :hello
hello
> Task :world
world
> Task :main2
main

5.自定义属性

1
2
3
4
5
6
7
//其实就是闭包
ext {
name = 'tom'
age = 18
}
ext.father = 'jerry'

第四章:Gradle任务

1.task的属性

配置项 描述 默认值
type 基于一个存在的task来创建,类似类继承 DefaultTask
overwrite 是否替换已存在的task,和type一起使用 false
dependsOn 配置task的依赖 []
action 添加到任务中的一个Action或闭包 null
description task的描述 null
group task的分组 null
1
2
3
4
5
6
7
//1.闭包内声明
task taskProperties {
description 'task的属性'
}
//2.闭包外赋值
taskProperties.group = BasePlugin.BUILD_GROUP

2.<<操作符

其实是doLast的短标记形式。

3.任务执行顺序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//1.doFirst doSelf doLast
class CustomTask extends DefaultTask {
@TaskAction
def doSelf() {
println 'execute doSelf'
}
}
def Task myTask = task exampleTask(type: CustomTask)
myTask.doFirst {
println 'execute doFirst'
}
myTask.doLast {
println 'execute doLast'
}
输出结果:
> Task :exampleTask
execute doFirst
execute doSelf
execute doLast
//2.shouldRunAfter mustRunAfter
task Task1 << {
println 'task1'
}
task Task2 << {
println 'task2'
}
task1.mustRunAfter task2
执行./gradlew task1 task2
输出结果:
> Task :Task2
task2
> Task :Task1
task1

4.任务开启和禁用

1
2
//禁止执行某项任务
Task1.enabled = false

5.onlyIf断言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
final String BUILD_ALL = "all"
final String BUILD_MIUI = "miui"
final String BUILD_HUAWEI = "huawei"
task MIUI_Release << {
println "MIUI Release"
}
task HUAWEI_Release << {
println "HUAWEI Release"
}
task buildApp {
dependsOn MIUI_Release, HUAWEI_Release
}
MIUI_Release.onlyIf {
def excute = false;
if (project.hasProperty("build_apps")) {
Object buildWhat = project.property("build_apps")
if (BUILD_ALL.equals(buildWhat) || BUILD_MIUI.equals(buildWhat)) {
excute = true;
}
}
excute
}
HUAWEI_Release.onlyIf {
def excute = false;
if (project.hasProperty("build_apps")) {
Object buildWhat = project.property("build_apps")
if (BUILD_ALL.equals(buildWhat) || BUILD_HUAWEI.equals(buildWhat)) {
excute = true;
}
}
excute
}
//1.两个渠道都打包
./gradlew -P build_apps=all buildApp
//2.打MIUI
./gradlew -P build_apps=miui buildApp
//3.打HUAWEI
./gradlew -P build_apps=huawei buildApp

第五六七章:Gradle插件

1.应用插件

1
2
apply plugin:'java'
apply plugin:org.gradle.api.plugins.JavaPlugin

2.应用脚本

1
apply from:'version.gradle'

3.应用第三方的插件

1
2
3
4
5
6
7
8
9
10
11
buildscript {
repositories {
jcenter()
}
dependebcies {
classpath 'com.android.tools.build:gradle:1.5.0'
}
}
apply plugin:'com.android.application'
需要配置classpath才能找到这个插件。

Android开发者建议尽量不使用Fragment

一、Fragment的优劣

  • 优点
    • 可以对手机和平板分别适配。
    • 将生命周期交给系统管理。
  • 缺点
    • 将生命周期交给系统管理。

对,你没看错,将生命周期交给系统管理在开发者不需要关注太多Fragment的生命周期时,这是非常方便的。但当开发者需要精确控制Fragment时,开发成本大大提高。

二、解决方案

经过上述讨论,关键点无非在于开发者是否需要精确控制一个界面的生命周期。
即使不需要精确控制生命周期,使用Fragment也会存在系统级别的Bug,并不建议使用。

生命周期无非是一个返回栈和场景切换操作,而场景用View即可实现。Activity最好只负责分发生命周期事件,返回栈和切换场景操作交由一个Controler管理,不同场景自身逻辑自己实现。这样,既把各自职责厘清,亦方便解耦和复用。

三、参考资料

git标签

一、创建标签

1
git tag -a <Tag Name> -m <Message>

二、查看Tag

1
git tag

三、删除Tag

1
git tag -d <Tag Name>

四、推送到远程仓库

1
2
3
4
//推送某一Tag
git push origin <Tag Name>
//推送所有Tag
git push origin --tags

五、删除远程仓库的Tag

1
2
3
4
//先本地删除Tag
git tag -d <Tag Name>
//再推送到远程仓库
git push origin :refs/tags/<Tag Name>