前段时间在我的知识星球里统计了一下使用kotlin开发的人,感觉还不错,有十多个人在工作中已经正式使用了,我的知识星球《Hi Android》欢迎你的加入,我也应星友的需求写了一部分的kotlin基础知识,我也还在学习的过程中,为了帮助更多的星友认识到Kotlin for Android,所以花了点时间整理了这篇《Kotlin超车指南》,如果对你有所帮助,记得点个赞哦。

Kotlin 是一个用于现代多平台应用的静态编程语言,由JetBrains开发。

Kotlin可以编译成Java字节码,也可以编译成JavaScript,方便在没有JVM的设备上运行。

Kotlin已正式成为Android官方支持开发语言。

推荐我的慕课网Android实战课程,助你暴力提升Android技术。
Android X/音视频开发/社交匹配算法/即时通信/语音识别/App优化/安全加固

一.Kotlin下载

Kotlin支持命令行,Eclipse,Intellij IDEA,Android Studio 3.0+ 四种方式编程,那么我们学习Kotlin基础,肯定是优先前三者, 只有在开始Android开发的时候才会选择Android Studio

1.命令行

命令行安装的话需要去Github上下载工具包

https://github.com/JetBrains/kotlin/releases/tag/v1.3.61

选择 kotlin-compiler-xxx.zip 即可。

2.Eclipse安装

安装Eclipse之前需要安装JDK,这个没意见吧,然后去Eclipse官网下载:

https://www.eclipse.org/downloads/

当然,就像ADT一样,如果想要Eclipse支持Kotlin开发,还需要下载Kotlin的插件

https://marketplace.eclipse.org/content/kotlin-plugin-eclipse

不过离线安装一般都是老版本的Eclipse了,在新版本中可以使用Eclipse商店进行在线安装,点击Eclispe菜单 - help - Eclipse Markerplace 搜索kotlin 就可以了。

3.Intellij IDEA

IDEA安装起来还是很方便的,点击链接:

https://www.jetbrains.com/idea/download/

下载自由版本即可。

4.Android Studio

Android Studio 也是如此,安装即可。

https://developer.android.google.cn/studio

二.Kotlin历史

1.Kotlin名称由来

Kotlin 来源于一个岛屿的名字,全称是 Kotlin Island,是英语「科特林岛」之意。这个小岛属于俄罗斯。

2.Kotlin版本迭代

2010 年 :JetBrains 着手开发 Kotlin。

2011 年 7 月 :JetBrains 公开宣布 Kotlin。

2012 年 2 月 :JetBrains 在 Apache 2 许可证下开源了 Kotlin 的源码

2016 年 2 月 :JetBrains 发布了 Kotlin 1.0 版,算是比较稳定的正式版。

2017 年 :1.1.2(2017 年 6 月)。相比 Kotlin 1.0 版本时,和 Kotlin 有关的代码数目从 210 万行飞升到 1000 多万行。

此后还在不断的更新中…

3.Kotlin语言特点

简洁

简洁时Kotlin最主要的特点。Kotlin中数据类,类型推导,Lambda表达式和函数式编程都可以大大减少代码行数,使得代码更加简洁。

安全

kotlin和Java一样都是静态类型语言

Kotlin支持非空和可空类型,默认情况下Kotlin数据类型声明的变量都是不能接受空值(null)的。

类型推导

Kotlin编译器可以根据变量所在的上下文环境推导出它的数据类型

支持函数式编程

作为现代计算机语言Kotlin支持函数式编程,函数式编程优点:代码变得简洁,增加线程安全和便于测试。

支持面向对象

Kotlin支持函数式编程,但也不排除面向对象。

Java具有良好的互操作性

Kotlin和Java具有100%互操作性,Kotlin不需要任何转换成包装就可以调用Java对象。反之亦然,Kotlin完全可以使用现有的Java框架或库

免费开源

Kotlin源代码时开源免费的,它采用Apache2 许可证。

三.Kotlin基础

1.输出

fun main(arg:Array<String>){println("Hello Kotlin!")
}

main函数是我们的主程序入口,在控制台输出Hello Kotlin使用了println方法。

2.输入

有输出就有输入,不过输入是从外部传递的

fun main(arg:Array<String>){println("请输入...")var a = readLine()println("你输入的内容是 $a")
}

3.变量与常量

fun main(arg:Array<String>){var name = "张三"name = "李四"println(name)val age = 18println(age)
}

我们用var代表变量,即可变的量,用val声明常量,即不可变的量

4.数据类型

数据类型和Java是类似的

Byte Short String Int Long Float Double

5.类型推导

类型推导也是kotlin的一个特色,我们来看代码

fun main(arg:Array<String>){var name:Stringvar age = 19
}

如果没有值就无法类型推导,则需要声明数据类型,如果有值,则可智能推导类型

6.函数

我们先来看下一段示例代码

//输出
fun print(text:String){println(text)
}//加法
fun add(a:Int,b:Int):Int{return a+b
}

首先是我们的输出函数,实际上所有的函数都有返回值的,但是有些不需要返回值,所有返回了一个Unit类型,也就是我们理解的无返回值,而加法两数相加之后需要把结果返回回去,则有了Int的返回值类型。

a.参数默认值

有时候碰到一些封装的场景,有对函数值统一要求的时候,可以这样处理

fun main(arg:Array<String>){println(add(1,2))println(add(b = 2))
}//参数默认值
fun add(a:Int = 5,b:Int):Int{return a+b
}

我给a默认赋值了一个5,如果使用默认值,则需要指定b = 2,如果不用此默认值,则直接传值即可,比重载好用。

7.字符串模板

在Java中要拼接字符串的话,需要很多的+号,但是有了字符串模板,一切都会变得简洁起来了

fun main(arg:Array<String>){val name = "张三"val address = "超市"val apple = 10val banana = 5//张三 去 超市 买了苹果和香蕉一共花了 15 元print("$name 去 $address 买了苹果和香蕉一共花了 ${apple + banana} 元")
}

如果用java写,你可以想象要怎么拼接

8.条件判断

条件判断我们有if语句

fun main(arg:Array<String>){val i = 10if(i < 5){println("i比5小")}else{println("i比5大")}
}

9.循环

循环使用in即可,在后面区间中使用

10.空类型

在Java中可能会出现空指针异常,但是在kotlin中是可以避免这种问题的,我们来看下空类型判断

fun main(arg:Array<String>){//noNull(null) 报错println(yesNull(null))
}//不能为null
fun noNull(text:String):String{return "Hello $text"
}//可以为null
fun yesNull(i:Int?):String{if(i === null){return "i == null"}return "Hello $i"
}

如果我传值指定了是String,那么null作为空类型是无法传入的,如果想要传入null,则需要加上问号?

11.选择表达式

在java中可以使用switch,在kotlin中则是when了

fun printScore(sex:Boolean,i:Int){when(i){100 -> print("最高成绩")80 -> {if(sex){print("男生这个分数不行")}else{print("女这个分数还行")}}else -> print("其他人都重考")}
}

并且不管我们的if还是when都是有返回值的,默认为表达式的最后一行

fun printScore(sex:Boolean,i:Int){val result = when(i){100 -> 10080 -> {if(sex){80}else{90}}else -> 60}print("result $result");
}

12.区间

区间很好理解,就是某个数到某个数之间,这里来计算一下从0到100的数字之和

fun main(arg:Array<String>){var a = 0..100var result = 0for(num in a){result = result + num}println("从0到100的数字总和: $result")
}

区间还有开区间(a…b)和闭区间[a…b]的概念
闭区间包含了端点的两个值

开区间不包含端点的两个值

13.List

fun main(arg:Array<String>){var a = listOf("吃早餐",1,"睡午觉",2)for(list in a){//取值println(list)}for((k,v) in a.withIndex()){//取下标与值println("k $k , v $v")}
}

我们可以通过listOf来创建list

14.map

键值对的存储,我们先简单理解一下

fun main(arg:Array<String>){var map = mapOf("Java" to 86, "Kotlin" to 92, "Go" to 78)for((k,v) in map){println("k $k , v $v")}
}

我们通过mapOf返回一个不可变的map

15.函数式编程

函数式编程是不同于过程式编程的另一种编程范式。函数式编程的思想在许多方面和过程式是冲突的,比如,过程式编程倾向于描述“怎么做”,而函数式编程则更倾向于描述“做什么”,过程式倾向于使用变量,而函数式则倾向于使用常量。尽管如此,函数式和过程式依旧是可以共存的,我们来看一个简单的例子:

fun add(a:Int,b:Int):Int{return a+b
}fun add1(a:Int,b:Int) = a+b
val add2 = {a:Int,b:Int -> a+b}

上一个是标准的函数写法, 而中间,则将表达式作为返回值,而add2则直接声明一个val接收参数计算,这完全就打破了我们之前的编程写法。

16.数据类型转换

类型转换用的最多的就是字符串转Int了,我们看代码:

fun main(arg:Array<String>){var a = "12"println(a.toInt())
}

其他转换也类型toLong,toString等。

17.递归

递归有两个概念,递归和尾递归,相当于调用自身,我们在java中也学过,再来看下尾递归,尾递归是一个新的概念,他的重要性在于它可以不在调用栈上面添加一个新的堆栈帧,而是更新它,如同迭代一般。

比如我们累加一个超级大的数,如果使用递归会出现堆栈溢出的吗,但是尾递归不会

fun main(arg:Array<String>){var result = 0println(add(100,result))
}tailrec fun add(i:Int,result:Int):Int{//println("result:$result")if(i == 0){return result} return add(i - 1,result + i)
}

18.单例模式

单例模式在java中有很多写法,但是在kotlin中就简单多了,只需要将class改为object即可,相当于在jvm内存中直接开辟了一块唯一内存地址。

但是使用object只是相当于Java的饿汉式,如:

//Java
public class JavaSingleton {private static JavaSingleton instance= new JavaSingleton();private JavaSingleton(){}public static JavaSingleton getInstance(){return instance;}
}
//Kotlin
object KotlinSingleton

如果我们需要实现双重校验的单例模式的话,需要利用伴生对象和lazy来实现:

//Java
public class JavaSingleton {private volatile static JavaSingleton instance;private JavaSingleton(){}public static JavaSingleton getInstance(){if(instance==null){synchronized (JavaSingleton.class){if(instance==null){instance=new JavaSingleton();}}}return instance;}
}
//kotlin
class KotlinSingleton private constructor() {companion object {val instance: KotlinSingleton by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { KotlinSingleton() }}
}

19.枚举类

枚举很简单,稍微看看就行

fun main(args: Array<String>) {println("现在是 ${Season.WINTER.name} 位于枚举第 ${Season.WINTER.ordinal} 个元素 ")
}//季节
enum class Season {SPRING,SUMMER,AUTUMN,WINTER
}

20.印章类

印章类又称为密封类,用来表示受限的类继承结构:当一个值为有限几种的类型, 而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合 也是受限的,但每个枚举常量只存在一个实例,而它的一个子类可以有可包含状态的多个实例

fun main(args: Array<String>) {var a = Son.chinaSon()var b = Son.foreignSon()a.Hello()b.Hello()
}
sealed class Son{fun Hello(){println("我是孩子")}class chinaSon:Son()class foreignSon:Son()
}

可以看到,假设中国人和外国人在一起生出的孩子,有可能是中国人的样貌,有可能是外国人的样貌取决于基因,那么我通过sealed来修饰。

21.数据类

数据类使用data修饰即可

22.延迟加载

延迟加载在kotlin中有两种,lateinit var 和 by lazy ,在kotlin中,默认属性都是空安全的,所以声明必须有初始化值,但是我们有时候是没有初始值的,这个时候就需要延迟加载了。

lateinit var 只能用于类中

class People {//报错var names:Stringlateinit var name:String
}

而by lazy 作为惰性加载,其使用第一次的时候才会为你加载

fun main(args: Array<String>) {    val p by lazy { People() }
}

我们一般常用的还是lazy,不过需要注意的是
1.by lazy 只能作为val关键字的属性

2.当属性用到的时候才会回调括号内的内容

23.伴生对象

伴生对象的关键字是companion,为外部模拟静态成员,可以半理解为static

class People {companion object PeopleInstnce {const val name: String = "张三"}
}fun main(args: Array<String>) {println("name ${People.name}")println("name ${People.PeopleInstnce.name}")

}

要注意的是,每个类只能定义一个伴生对象,这个伴生对象相当于外部类的对象,可以直接通过外部类名访问伴生对象的成员,这也是取消了static的一个弥补手段。

24.内联函数

内联的作用主要还是为性能这块所考虑,我们每一次调用高阶函数的时候,都会创建一个新的对象,所以你可以发现高阶函数都是内联函数,内联函数的关键字是lnline

当一个函数被声明为inline时,它的函数体是内联的,也就是说,函数体会被直接替换到函数被调用地方。

四. 面向对象

1.对象

和java一样,我们来看下

class People(var name: String, var sex: Boolean)fun main(args: Array<String>) {var p = People("张三", true);println("人类${p.name}他的性别是${if (p.sex) "男" else "女"}")
}

可以看到这里class定义一个类,然后声明他的参数,不需要去创建他的构造函数,实际上,这就是他的构造函数
那么构造函数,这里又有一些区分了,在kotlin中,有主构造和次构造的区别

而我们上述的写法真实情况是这样的,只不过我们一般省略关键字

class People constructor(var name: String, var sex: Boolean)

我们如果没有在主构造中对变量进行var/val的声明,则可以在init语句中进行赋值

class People(name: String, sex: Boolean) {private var name: String? = ""private var sex: Boolean? = falseinit {this.name = namethis.sex = sex}
}

当然,你也可以直接赋值,这也算写法上的演进

class People(name: String, sex: Boolean) {private var name: String? = nameprivate var sex: Boolean? = sex
}

那么再来看下次构造,在Java中,构造函数是必须和类同名的,但是kotlin中则不是,我们可以这样

class People {constructor(name: String)constructor(name: String, sex: Boolean)
}fun main(args: Array<String>) {People("张三")People("李四", true)
}

2封装

封装和java是一样的,只要不对外提供的代码进行private修饰即可,默认public

3.继承

继承的概念和java类似,但是还是有一些不一样的,我们来看下代码

open class People(var name: String, var sex: Boolean) {open fun Eat() {println("People Eat")}open fun Sleep() {println("People Sleep")}open fun Character() {println("People Character")}
}class Boy(name: String, sex: Boolean) : People(name, sex) {override fun Character() {println("Boy Character")}
}fun main(args: Array<String>) {val boy = Boy("张三",true);boy.Eat()boy.Sleep()boy.Character()
}

在这段代码中,我定义了一个People,他有吃,睡,性格,三个函数,现在一个男孩继承了他,并且重写了性格的函数,因为每个人的性格都是不一样的,这里和java需要注意的问题就是,在java中我们继承了就可以直接使用父类,但是在kotlin中,父类需要标记open这个关键字才能让人继承,并且子类重写方法需要加上overide

4.抽象

我们看继承贴出的那些代码片段可以发现,其实很多东西我们可以优化的,比如People作为父类没必要实现具体操作,可以抽象出来:

abstract class People(var name: String, var sex: Boolean) {abstract fun eat()abstract fun sleep()abstract fun character()
}class Boy(name: String, sex: Boolean) : People(name, sex) {override fun eat() {println("Boy eat")}override fun sleep() {println("Boy sleep")}override fun character() {println("Boy character")}
}fun main(args: Array<String>) {val boy = Boy("张三", true);boy.eat()boy.sleep()boy.character()
}

可以看到,我们通过abstract去优化了这个抽象类,而Boy类具体去实现

5.多态

多态我们可以看抽象类的延伸,即同种功能不同的实现

abstract class People(var name: String, var sex: Boolean) {abstract fun character()
}class Boy(name: String, sex: Boolean) : People(name, sex) {override fun character() {println("$name ${if (sex) "调皮" else "乖巧"}")}
}class Girl(name: String, sex: Boolean) : People(name, sex) {override fun character() {println("$name ${if (sex) "调皮" else "乖巧"}")}}fun main(args: Array<String>) {val boy = Boy("张三", true);boy.character()val girl = Girl("李四", false);girl.character()
}

比如一个People的性格,男人和女人实现的内容是不一样的。

6.接口

接口使用的关键字是interface,比如我模拟一下点击事件

fun main(args: Array<String>) {//点击事件click(object :OnClickListener{override fun onClick(position: Int) {println("position:$position")}})
}fun click(listener: OnClickListener){listener.onClick(2)
}interface OnClickListener {fun onClick(position: Int)
}

7.委托和代理

委托和代理是相辅相成的,打个比方,政府招商的一块地,一千万委托给了开发商A,这个时候就是政府委托开发商,而开发商代理了政府,那么这个时候开发商A已一百万的价格委托给了开发商B,从中牟利了九百万,也就导致了现在的豆腐渣工程了,那么我们用代码来实现吧。

fun main(args: Array<String>) {val build = developersA("一千万")build.buildHome()
}class developersB(var price: String) : IBuildHome {override fun buildHome() {println("建造房子花费$price")}
}class developersA(var price: String) : IBuildHome by developersB("一百万")//建造方式的能力
interface IBuildHome {fun buildHome()
}

可以看到我们是通过by关键字进行委托的,developersA 获得一千万后给developersB一百万依旧把房子建造出来了。

五.函数式编程

我们在讲kotlin基础的时候实际上是有讲函数式编程的,但是那些都比较粗糙了,这一章节我们讲细一点

1.闭包

我们需要先理解闭包的概念,因为后面讲高阶函数的时候

1.闭包指的是函数的运行环境

2.闭包可以持有函数的运行环境

3.函数内部可以定义函数

4.函数内部也可以定义类

5.在函数中返回一个函数,被返回的函数可以调用主函数的属性

这样可能理解有点抽象,事实上,作为kotlin的特性之一,闭包的用途还是很广泛的,全局变量,顾名思义,其作用域是当前文件甚至文件外的所有地方;而局部变量,我们只能再其有限的作用域里获取。

那么,如何在外部调用局部变量呢?答案就是——闭包,与此给闭包下个定义:闭包就是能够读取其他函数内部变量的函数

fun main(args: Array<String>) {val add = add()add()add()add()//输出 1 2 3
}fun add(): () -> Unit {var count = 0return fun() {println(++count)}
}

这段代码中可以看到输出的是 1 2 3 ,也就是在return的fun中引用了外部的count

2.forEach

forEach是高阶函数之一,我们先来看下他的用法

fun main(args: Array<String>) {val lists = listOf(1,2,3,4,5,6)lists.forEach {println(it)}
}

直接就能打印lists的参数,而要想了解他的工作原理,我们最好来看下他的源码

/*** Performs the given [action] on each element.*/
@kotlin.internal.HidesMembers
public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {for (element in this) action(element)
}

可以看到他是Iterable的扩展函数,接收的是一个action参数,T就是list的类型,也就是

带有Int类型无返回值的函数

而内部则是通过for遍历传入下标得到具体值

还有一个forEachIndexed则是求下标和具体值的,这个自己理解一下

3.apply

apply函数扩展了所有的泛型对象,在闭包范围内可以任意调用该对象的任意方法,并在最后返回该对象.

我们来看一段示例代码

class People {val name: String = "小明"val age: Int = 18
}fun main(args: Array<String>) {//方式一val p1 = People();println("p1 ${p1.name} ${p1.age} ")//方式二People().apply {println("p1 $name $age")}
}

在闭包内我们可以随意获取和变化参数并且返回对象本身,我们来看下他的源码

@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {contract {callsInPlace(block, InvocationKind.EXACTLY_ONCE)}block()return this
}

这段代码中T表示对象本身,并且内部又一个契约contract,用于上下文推断。

4.maxBy

求最大值

fun main(args: Array<String>) {val lists = listOf(11,2,30,49,50,6)val max = lists.maxBy { it }println(max)
}

我们可以传递一个类型进去,他则返回一个类型的最大值,来看下源码

public inline fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R): T? {val iterator = iterator()if (!iterator.hasNext()) return nullvar maxElem = iterator.next()if (!iterator.hasNext()) return maxElemvar maxValue = selector(maxElem)do {val e = iterator.next()val v = selector(e)if (maxValue < v) {maxElem = emaxValue = v}} while (iterator.hasNext())return maxElem
}

这段源码实际上就是在遍历获得最大值,通过R返回回去,当然,还有minBy求最小值

5.fifter

过滤函数,要啥RxJava,要啥自行车,kotlin美滋滋

fun main(args: Array<String>) {val lists = listOf(11, 2, 30, 49, 50, 6)//求大于20且小于50的值val filter = lists.filter { (it > 20) and (it < 50)}println(filter)
}

这里可以多条件判断,只要符合规范即可。
看源码得知最终调用的是filterTo

6.map

map作为数据转换,根据规则创建新的集合

fun main(args: Array<String>) {val lists = listOf(11, 2, 30, 49, 50, 6)val filter = lists.map {it.toFloat()}println(filter)
}

这里我对值进行了toFloat的操作,则全部类型变换为float.
看源码得知最终调用的是mapTo,但是可以知道是创建了一个ArrayList进行的返回

7.any

any更多的是作为一个判断函数使用

fun main(args: Array<String>) {val lists = listOf(11, 2, 30, 49, 50, 6)//集合中是否有30这个值val filter = lists.any {it == 30}println(filter)
}

来看下源码

public inline fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean {if (this is Collection && isEmpty()) return falsefor (element in this) if (predicate(element)) return truereturn false
}

传递的参数是一个T的集合类型返回的是一个布尔的函数,可以看到他的实现也是通过for循环遍历的

8.count

count作为满足条件的统计函数,我们可以这样使用

fun main(args: Array<String>) {val lists = listOf(56, 77, 30, 49, 100, 63)//统计及格的同学人数val filter = lists.count {it >= 60}println(filter)
}

从源码中也可以看出是通过for循环去遍历统计size的

9.find

查找函数,只返回满足条件的第一个

fun main(args: Array<String>) {val lists = listOf(56, 77, 30, 49, 100, 63)//查找第一个及格的同学val filter = lists.find {it >= 60}println(filter)
}

看源码得知最终调用的是firstOrNull

10.groupBy

这是分组函数,用于一个特定条件的分组

fun main(args: Array<String>) {val lists = listOf(56, 77, 30, 49, 100, 63)//及格和不及格的分组val groupBy = lists.groupBy {it >= 60}println(groupBy)
}

比如这个示例,我的条件是大于等60则一组,那么其余为一组,可得及格和不及格的分组信息

11.let

let的作用主要用于避免非空的判断和作用域替换

name?.let{//只有不为空才会走进来
}

六.DSL

DSL领域特定语言,即好玩又好吃的语法糖。

1.扩展函数

Kotlin的扩展函数可以让你作为一个类成员进行调用的函数,但是是定义在这个类的外部。这样可以很方便的扩展一个已经存在的类,为它添加额外的方法。在Kotlin源码中,有大量的扩展函数来扩展java,这样使得Kotlin比java更方便使用,效率更高。

我们来举个例子:

fun main(args: Array<String>) {val lists = listOf(56, 77, 30, 49, 100, 63)println(lists.getIndex())
}
//扩展:获取第一个下标
fun List<Int>.getIndex():Int{return get(0)
}

我现在想获取List的第一个值,但是如果List并没有这个方法,我则可以直接给予他扩展。

2.中缀表达式

像我们的and or in 都是中缀表达式,实际上就是省略了点的操作

fun main(args: Array<String>) {Boy().love(Girl())Girl() love Boy()
}class Boy{fun love(girl: Girl){//普通写法}
}class Girl{infix fun love(boy: Boy){//中缀表达式}
}

可以看到,是相当的有趣。

七.Kotlin For Android

关于Kotlin开发Android应用的时候的一些区别

1.创建项目

创建项目的时候,在Configure your peoject 这一项的时候选择kotlin作为开发语言即可

大体的东西都不会变化,只是增加了对Kotlin的支持,包括在project/build.gradle中增加了kotlin的插件

以及在app/build.gradle中增加了kotlin的stdlib和core库,当然还包括了kotlin的扩展库

2.findViewById

kt是不需要自己手动findviewbyid的,我们可以用个扩展插件来完成,先来看一段代码

import kotlinx.android.synthetic.main.activity_main.*class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)mButton.text = "Button"mButton.setOnClickListener {Log.i("TAG", "Button Click")}}
}

在这段代码中,我们引入了一段包名

import kotlinx.android.synthetic.main.activity_main.*

我们就可以直接省略初始化的操作,使用id就可以了
这个功能就是kotlin扩展库的功能了

3.跳转界面

//Java
startActivity(new Intent(this,FirstActivity.class))
//Kotlin
startActivity(Intent(this,FirstActivity::class.java))

跳转主要还是在class类上,我们可以看到Kotlin需要::class.java

4.匿名内部类

mButton.setOnClickListener(object :View.OnClickListener{override fun onClick(v: View?) {//Anything}
})
//可简化
mButton.setOnClickListener { }

5.Anko

这是一个优秀的kotlin辅助库,也可以称之为工具库:

https://github.com/Kotlin/anko

a.代码布局

可以使用它的一些语法糖来实现代码写布局,虽然我觉得这个使用率肯定是不高的

verticalLayout {gravity = Gravity.CENTERval name = editText()val password = editText()name.hint = "请输入账号"password.hint = "请输入密码"button("登录") {onClick {toast("登录成功")}}
}

我们来运行看一下

b.Intent 优化

intent跳转也相对的简化了

//需要设置FLAG
startActivity(intentFor<FirstActivity>("id" to 5).singleTop())
//需要传递参数
startActivity<FirstActivity>("id" to 5)
//仅适用跳转
startActivity<FirstActivity>()

c.其他

还有log的优化,以及toast,dialog等,大家自己去发现吧。

八.实战案例一:天气预报

这里我准备写一个Kotlin版本的天气预报来给各位演示下一些Koltin语法的基本使用,先来看下效果图

功能也很简单,共四个页面

  • 1.启动页,缩放动画
  • 2.城市选择页,自定义View实现城市选择,RecyclerView与城市选择View双向绑定和联动
  • 3.主页,天气详情,RecyclerView显示五天天气
  • 4.设置页,重新选择城市等

使用的接口是聚合数据

使用的网络请求库是retrofit2,好了,我们开始吧;

1.启动页

启动页就一个动画

这里使用的是ViewCompat自带的动画,追其根源的话最终还是属性动画实现,监听动画结束之后就可以判断是否选择过城市了,选择过就直接进入主页,没有的话就进入城市选择页,这里作为持久化保存,我是通过Kotlin的单例封装的一个SharedPreferences类

2.城市选择页

城市选择页比较麻烦,我们先来定义请求网络的接口

然后就是一层简单的封装了

这里首先是对类进行了object的单例化,然后对retrofit2进行了延迟初始化,当我们加载城市列表成功之后,我们就将数据设置给我们的侧边城市选择View,这里我贴一下核心的代码

首先就是绘制了,将34个城市名称按照View的高度进行平均分配和绘制,然后紧接着就是滑动的处理了

这样,我们就可以很轻松的实现列表的滑动了,但是这里又有一个问题了,那就是联动的问题

a.View -> RecyclerView

先看选择View控制列表的滑动

我这里的做法就是根据他的滑动坐标点,找到对应的城市名,然后根据城市名去过滤城市列表以此来找到index,这样就可以滚动列表了

b.RecyclerView -> View

这个是反向的操作,我们需要监听列表的滚动

得到第一个可见的下标后以此来推敲出城市名,然后去根据城市名得到index,让View去刷新即可

3.主页

主页的操作其实就是按部就班的将请求的数据显示出来

4.设置页

设置页也是一样的,这里多了个粘贴板的操作罢了

5.Gif预览

最后我们来预览下Gif

九.结语

Kotlin之美还有很多,一文很难讲完,但是循序渐进,还是可以看到效果的,这篇文章的初衷还是希望带领大家走进这门语言,虽然Google强调Kotlin First ,但是就目前而言还只是应用App还没设计到Android 源码层的改动,所以还是百花齐放的阶段,留给大家的时间还是有的,希望大家再接再厉吧。

Github地址:

https://github.com/LiuGuiLinAndroid/Kotlin

推荐我的慕课网Android实战课程,助你暴力提升Android技术。
Android X/音视频开发/社交匹配算法/即时通信/语音识别/App优化/安全加固

如果有兴趣的话,可以加入我的Kotlin学习小组

我的公众号,期待你的关注

Kotlin 超车指南相关推荐

  1. Kotlin实战指南二十:flow

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/117370700 本文出自[赵彦军的博客] 文章目录 往期精彩文章 flow 是啥 ...

  2. Kotlin实战指南十九:use 函数魔法

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/117366756 本文出自[赵彦军的博客] 文章目录 往期精彩文章 use函数 往期 ...

  3. Kotlin实战指南十八:open、internal 关键字使用

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/117365712 本文出自[赵彦军的博客] 文章目录 往期精彩文章 open关键字 ...

  4. Kotlin实战指南十七:JvmField、JvmStatic使用

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/116668666 本文出自[赵彦军的博客] 文章目录 往期精彩文章 @JvmFiel ...

  5. Kotlin修炼指南(三)——奇技淫巧

    Kotlin作为Android开发的首选语言,为开发者提供了大量的语法糖和技巧,让开发者可以专注于需求开发,而将语言所带来的影响减少到最少.Java和Kotlin最大的区别,实际上在于Kotlin的函 ...

  6. Kotlin实战指南十六:Synchronized、Volatile

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/116267707 本文出自[赵彦军的博客] 文章目录 如何创建线程 Thread 如 ...

  7. Kotlin实战指南十四:协程启动模式

    转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/96008400 本文出自[赵彦军的博客] 文章目录 协程启动 DEFAULT LA ...

  8. Kotlin实战指南十三:协程

    转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/95626034 本文出自[赵彦军的博客] 文章目录 前言-协程介绍 主流语言对协程 ...

  9. Kotlin实战指南十二:data class

    转载请标明出处:https://blog.csdn.net/zhaoyanjun6/article/details/94649274 本文出自[赵彦军的博客] 文章目录 前言 正文 toString( ...

最新文章

  1. minhash pyspark 源码分析——hash join table是关键
  2. Lintcode 1230解题思路和c++代码
  3. djc加密数字货币_中国银行原副行长: quot;网络加密币quot;难以成为货币,央行数字货币只能是法定货币的数字化...
  4. 2020 我的C++学习之路 C++PrimerPlus第七章课后习题
  5. XAMPP环境下apache无法启动(端口未被占用)的解决方法
  6. Qt Creator添加套件
  7. Python基础(一)简介与安装
  8. 宏定义和Typedef区别?
  9. Heron 数据模型,API和组件介绍
  10. 高效率去掉js数组中重复项
  11. Hadoop2.x介绍与源代码编译
  12. 标点符号/特殊符号的英文名称
  13. 51nod 1050循环数组最大字段和
  14. 软件测试用mac还是windows,Boot Camp还是虚拟机?Mac+Win实测
  15. VB2010的时间表示
  16. Cisco Packet Tracer 思科模拟器交换机的链路聚合技术
  17. (译)Xposed Helpers
  18. python借助OpenCC实现中文繁体转简体
  19. 用MODIS数据借助MATLAB绘制世界植被分布图
  20. Sprite 3D用法和相关特性详解

热门文章

  1. 清华大学计算机学院博士后在学待遇,清华大学博士后待遇怎么样
  2. FATE框架实战(一)
  3. CI130X智能语音芯片应用于空调伴侣,可实现离线语音控制空调,风扇,灯具,电视等,最多支持500条命令词
  4. 邂逅、啡咖、美女、狗屎理论,痞子蔡又回来了
  5. 模拟退火法和蚂蚁优化算法求解TSP问题(Matlab代码实现)
  6. 数据链路层的检错技术——循环冗余校验CRC(Cyclic Redundancy Check)
  7. 送给结婚纪念日,致亲爱的妻子
  8. security_huks模块下hks_rkc.c代码评注第一部分
  9. 沈孝钧计算机算法基础答案,计算机算法基础教学课件ppt作者沈孝钧第12章-PPT-N2课件.pptx...
  10. 【企业了解】闪迪与西部数据