Fellow Travellers

Kotlin初识及底图切换代码分析

陈广禄
字数统计: 3k阅读时长: 12 min
2018/11/23 Share

Kotlin初识、及底图切换代码分析


简介

Kotlin是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。在Kotlin 语言出现之前,几乎所有的安卓应用程序都是使用Java语言编写的。但在2017年5月,google宣布Kotlin成为安卓的官方语言后,经过半年的发展,使用Kotlin 的开发者中5%增长到了15%,并且还在呈现上升趋势。
2017年9月29日,1.2Beta版发布。并宣布 Kotlin 成为 Android 官方开发语言。它即可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。那么我们为何要使用Kotlin?官方给出四个答案:简洁、安全、兼容(JAVA 安卓 REACT)、工具友好(任何JAVA开发IDE均可)。

首现给大家推荐几个学习地址,学习起来比较容易些:

Kotlin官方文档

Kotlin中文文档

kotlin开发者社区

菜鸟教程地址

Kotlin官方代码示例

Kotlin从入门到放弃系列视频


下面讲解下Kotlin和java相比优势是什么?

  • 更简洁:这是它重要的优点之一,可以比Java编写少得多的代码。
  • 实例化对象:相比较Java而言,在Kotlin中实例化对象无需new关键字
  • 更安全:Kotlin是空安全的,它在编译期间就会处理各种为null的情况,无需像java一样添加很多的判空代码,节约很多调试空指针异常的时间,很大程度上避免出现NullPointException。
  • 易扩展:扩展函数意味着我们不仅可以扩展我们原有写好的类,还可以扩展系统级的类,非常灵活,另外如果在类里编写扩展函数,那么只对当前类生效。
  • 函数式:Kotlin使用了很多函数式编程的概念,比如用到了lambda表达式来更方便地解决问题。
  • Kotlin Android Extensions:再也不用编写烦人的findViewById()了,如果你集成了ButterKnife,是时候删除对它的依赖了,Kotlin支持了对于View以id形式访问。
  • 拒绝分号:如果开发Java会发现,我们在写好一个方法后都需要加上分号,来标志这句话或这个方法的结束。使我们养成了习惯。对于kotlin来说,不需要写分号这一点真是节省了很多时间,对于一天写成百上千行甚至上万行代码的童鞋来说,相当于省了多少个分号。
  • 强大之处(兼容性):它是一门静态语言,支持多种平台,包括移动端、服务端以及浏览器端,此外,Kotlin还是一门融合了面向对象与函数式编程的语言,支持泛型、安全的空判断。兼容JAVA、 安卓 和REACT,并且Kotlin与Java可以做到完全的交互。

简洁性

java代码:类里就两个字段,一个id一个name

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class User {
private long id;
private String name;
public void setId(long id) {
this. id = id;
}
public void setName(String name) {
this. name=name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}

kotlin代码:这一句代码就够了,Kotlin会自动生成所有属性和它们的访问器,以及一些方法,例如toString方法及equals方法。

1
data class User(var name: String, var id: String)

使用说明:编译器自动从主构造函数中声明的所有属性导出以下成员

  • equals()/hashCode() 对;
  • toString() 格式是 “User(name=John, age=42)”;
  • componentN() 函数 按声明顺序对应于所有属性;
  • copy() 函数

注: Data Class 是一个final类

  • 构造函数中至少有一个参数
  • 构造函数中的参数都需要声明var 或者val
  • data class不能是抽象的,可继承的,或者内部类,因为类本身是final类型
  • 如果需要显示的声明一个无参的构造方法,需要给构造方法里面的参数设置默认值

实例化对象

在kotlin中无需new对象,定义变量user,直接给对象传入参数值即可

1
var user = User("kotlin","123")

空安全

当我们用Java写代码时,我们如果不想出现NullPointerException,我们需要在使用它之前每次去判断是否为空。而Kotlin这类空安全语言默认对象和字段不能为空,如果我们非要让一个字段或对象为空,那么必须使用安全操作符(?)来指定。

1
2
var user: User? = null
toast(user.name)

如上代码编译是无法通过的,因为user有可能为null,而user没对空情况做处理,所以无法编译。解决方式有两种:
//第一种:利用安全调用操作符,只有在user不为空时会调用user.name,否则调用toast(null)

1
toast(user?.name)

//第二种:或者我们也可以给它赋一个默认值,当user为空时调用toast(“kotlin”)

1
toast(user?.name ?: "kotlin")

易扩展

kotlin允许我们对任何类添加方法,包括系统级的类,自定义类等等,比如我想在Context类中添加一个toast方法。

1
2
3
fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) { 
Toast.makeText(this, message, duration).show()
}

函数式

kotlin支持Lambdas表达式
正常写法为:

1
2
3
4
5
view.setOnClickListener(object : OnClickListener {
override fun onClick(v: View) {
toast("Click")
}
}

Lambdas表达式写发为:大大节俭了代码量

1
2
 view.setOnClickListener({view -> toast("Click")}}
}

Kotlin Android Extensions

#####在开发中初始化控件时必不可少的,每次都要findViewById这样很麻烦。或许有些人为了方便采用注解形式,例如ButterKnife、Annotations等注解框架。但也避免不了在代码中加上一些注解代码。随着控件变多,注解也会随之增多。

1
2
3
4
5
6
7
8
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lnLeft = findViewById(R.id.ln_left);
tvNice = findViewById(R.id.tv_nice);
ivBack = findViewById(R.id.iv_back);
}

Kotlin是怎样初始化控件的呢:
kotlin提供了另外一个思路,直接通过id来绑定。
首先在appbuilde.gradle中添加 ‘kotlin-android-extensions’。并导入import kotlinx.android.synthetic.main.activity_main.*即可。则导入了布局文件Id集合,可直接使用ID名对其控件进行操作

1
2
lnLeft.text="Hello"
tvNice.text="kotlin"

拒绝分号

如上是否有看到“;”的展示呢,这就是Kotlin的强大之处。


函数说明

fun main(args:Array<String>){ 
println(Hello Kotlin!)
}
  • fun 函数声明,固定写法
  • main 方法程序入口
  • 接受参数名是args,数据类型是String
  • 向控制台打印输出

常用语法

关键字

Fan:函数定义使用。格式为(参数:类型)
var:定义可变变量
val:定义不可变变量
In:定义区间
is:类型判断符
If:包含一个布尔类型表达式和一条或多条语句,和Java相同
when:将它的参数和所有的分支条件顺序比较,直到某个分支满足条件,和java中switch语句类似
for、while::循环遍历,和java类似
(以上均支持break和return)

数据类型

4.2.1 基本数据类型包括:Byte、Short、Int、Long、Double等
4.2.2 kotlin没有自动向上转型,如Int转Long,需调用toLong方法

1
2
var a:Int=10 
var b:Long=a.toLong()

Kotlin常用符号

  • :用于类的继承,变量的定义
  • in 表示区间的意思
  • $ 转换符号
  • : :是将方法作为参数,传递到另一个方法中使用。
  • ? 表示当前对象是否可空
  • !! 表示当前对象不为空时执行
  • “”” 表示输入多行文本,输入的内容将会原样保留
  • @ 限定this类型

字符串模版

1
2
3
4
5
6
7
8
9
10
11
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val arr = arrayOf("hello", "China")
stringTemplate(arr)
}

private fun stringTemplate(args: Array<String>) {
if (args.isNotEmpty())
println("args[0] = ${args[0]} \n args[1] = ${args[1]}")
}

结果为:

1
2
args[0] =hello
args[1] =China

Kotlin中条件表达式

1
2
3
4
5
6
7
fun max(a: Int, b: Int): Int {
if (a > b) {
return a
} else {
return b
}
}

Kotlin 中 if 条件表达式省略写法:

1
fun max2(a: Int, b: Int) = if (a > b) a else b

for 循环的使用

Kotlin 中使用的 for 循环,相比于 Java 中而言,要简介了很多。主要分为两种形式:一种是 in 关键字,in 关键字是直接使用数组中的对象进行循环,判断变量是否存在,如果存在续集循环,如果不存在,停止循环;一种是 indices 方法,indices 就是通过索引来进行循环的一种方式。代码实例如下:
in关键字的 for 循环:

1
2
3
4
val arr = arrayOf(1, 3, 4, 5, 6)
for (num in arr) { //直接使用数组中的对象循环
println(num)
}

indices 方法的 for 循环:

1
2
3
4
val arr = arrayOf(1, 3, 4, 5, 6)
for (i in arr.indices) { //通过索引循环
println(arr[i])
}

Kotlin中When条件表达式

在 Kotlin 中的 when 表达式和 Java 中的 switch 表达式有些类似,但是省略了 case 和 break,而且支持各种不同的类型,Java 中的 switch 表达式只是支持单一类型。

1
2
3
4
5
6
7
8
9
 fun chose(obj: Any) {
when (obj) {
1 -> print("Is Int")
"Hello" -> print("Hello Kotlin")
is Long -> print("Long")
!is String -> print("Not a string")
else -> print("Unknown") // 默认,相当于switch的default
}
}

ranges 的使用

使用 in 运算符检查数字是否在某一个范围之内

1
2
3
4
5
if (x in 1..y-1) { ... } // 1..y-1表示1到y-1的范围
for (i in 1..100) { ... } // 遍历1到100范围
for (i in 1 until 100) { ... } // 半开范围不包括100,相当于[1,100)
for (x in 2..10 step 2) { ... } // 每次夸2,内容为2,4,6,8,10
for (x in 10 downTo 1) { ... } // 返序

使用 in 运算符检查字符串区间

1
2
3
4
 fun main(args: Array<String>) {
println('a'<'c') //比较大小,可以忽略不看
println("kotlin" in "java".."scala")
}

使用 in 运算符检查集合

1
2
3
fun main(args: Array<String>) {
println("kotlin" in setOf<String>("java","scala"))
}

Kotlin中Get和Set方法

1
2
3
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]

格式就如上所示, set和get可写也可不写, 不写的话会有默认的实现, 需要注意的是val修饰的变量是没有set方法的, 也不允许重写set方法, 编译不通过!
下面是一个完整的代码:

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
53
54
55
class Student {
var name : String = "zhang"
// 这里使用field而不是使用lastName, 是因为如果使用lastName会造成递归调用从而造成内存溢出, 因为使用lastName也会涉及到调用set/get的问题
get() = field.toUpperCase()

var no : Int = 0
get() = field
set(value) {
if (value < 10) {
field = value
} else {
field = -1
}
}

var classTeacher : String? = "孔子"
set(value) = if (value == null) {
field = "李白"
} else {
field = value
}
/*set(value) = if (value == null) {
this.classTeacher = "李白"
} else {
this.classTeacher = value
}*/

var isKZ : Boolean = true
get() {
return this.classTeacher == "李白"
}

var className : String ? = "1班"

}

fun main(args: Array<String>) {
var stu: Student = Student()

stu.name = "wang"
println("lastName:${stu.name}")

stu.no = 9
println("no:${stu.no}")

stu.no = 20
println("no:${stu.no}")

stu.classTeacher = null
println(stu.classTeacher)
println(stu.isKZ)

stu.className = "一年一班"
println(stu.className)
}

运行结果如下:

1
2
3
4
5
6
lastName:WANG
no:9
no:-1
李白
true
一年一班

filed用法:它的作用就类似于java里的this.属性名, 例如上面代码中的 get() = field.toUpperCase(), 就相当于java里的 this.name.toUpperCase(),但是不能直接使用this.name会造成递归调用内存溢出的,因为在set和get中是不允许有和属性本身相同名字的局部变量,属性的调用也涉及到了set/get会造成递归调用, 所以要解决引用自身的问题, kotlin发明了field(后端变量)来解决这个问题
如下例子也是没有问题的:

1
2
3
4
5
6
var test : Int = 0
get() {
var t = 1
field = t
return field
}


总结

由于时间原因kotlin语法先讲到这里,常用且频繁出现的。后续文档还会进一步更新!文章内容作为铺垫,接下来我们一起学习下底图切换的内容!代码没有贴出,详见项目代码。以上就是我对kotlin的部分理解与说明,感谢你花费时间阅读这篇文章,祝您生活愉快!

CATALOG
  1. 1. Kotlin初识、及底图切换代码分析
    1. 1.1. 简介
      1. 1.1.1. 首现给大家推荐几个学习地址,学习起来比较容易些:
        1. 1.1.1.1. Kotlin官方文档
        2. 1.1.1.2. Kotlin中文文档
        3. 1.1.1.3. kotlin开发者社区
        4. 1.1.1.4. 菜鸟教程地址
        5. 1.1.1.5. Kotlin官方代码示例
        6. 1.1.1.6. Kotlin从入门到放弃系列视频
    2. 1.2. 下面讲解下Kotlin和java相比优势是什么?
      1. 1.2.1. 简洁性
      2. 1.2.2. 实例化对象
      3. 1.2.3. 空安全
      4. 1.2.4. 易扩展
      5. 1.2.5. 函数式
      6. 1.2.6. Kotlin Android Extensions
      7. 1.2.7. 拒绝分号
    3. 1.3. 函数说明
    4. 1.4. 常用语法
      1. 1.4.1. 关键字
      2. 1.4.2. 数据类型
      3. 1.4.3. Kotlin常用符号
      4. 1.4.4. 字符串模版
      5. 1.4.5. Kotlin中条件表达式
      6. 1.4.6. for 循环的使用
      7. 1.4.7. Kotlin中When条件表达式
      8. 1.4.8. ranges 的使用
        1. 1.4.8.1. 使用 in 运算符检查数字是否在某一个范围之内
        2. 1.4.8.2. 使用 in 运算符检查字符串区间
        3. 1.4.8.3. 使用 in 运算符检查集合
      9. 1.4.9. Kotlin中Get和Set方法
    5. 1.5. 总结