Kotlin 与 Android
什么是Kotlin?
Kotlin,它是JetBrains开发的基于JVM的语言。JetBrains因为创造了一个强大的Java开发IDE被大家所熟知。Android Studio,官方的Android IDE,就是基于Intellij,作为一个该平台的插件。
Kotlin是使用Java开发者的思维被创建的,Intellij作为它主要的开发IDE。对于Android开发者,有两个有趣的特点:
对Java开发者来说,Kotlin是非常直觉化的,并且非常容易学习。语言的大部分内容都是与我们知道的非常相似,不同的地方,它的基础概念也能迅速地掌握它。
它与我们日常生活使用的IDE无需配置就能完全整合。Android Studio能够非常完美地理解、编译运行Kotlin代码。而且对这门语言的支持来正是自于开发了这个IDE的公司本身,所以我们Android开发者是一等公民。
但是这仅仅是开发语言和开发工具之间的整合。相比Java 7的优势到底是什么呢?
- 它更加易表现:这是它最重要的优点之一。你可以编写少得多的代码。
- 它更加安全:Kotlin是空安全的,也就是说在我们编译时期就处理了各种null的情况,避免了执行时异常。如果一个对象可以是null,则我们需要明确地指定它,然后在使用它之前检查它是否是null。你可以节约很多调试空指针异常的时间,解决掉null引发的bug。
- 它是函数式的:Kotlin是基于面向对象的语言。但是就如其他很多现代的语言那样,它使用了很多函数式编程的概念,比如,使用lambda表达式来更方便地解决问题。其中一个很棒的特性就是Collections的处理方式。
- 它可以扩展函数:这意味着我们可以扩展类的更多的特性,甚至我们没有权限去访问这个类中的代码。
- 它是高度互操作性的:你可以继续使用所有的你用Java写的代码和库,因为两个语言之间的互操作性是完美的。甚至可以在一个项目中使用Kotlin和Java两种语言混合编程。
Kotlin的用途
服务器端
使用 Kotlin 进行服务器端开发
Kotlin 非常适合开发服务器端应用程序,允许编写简明且表现力强的代码, 同时保持与现有
基于 Java 的技术栈的完全兼容性以及平滑的学习曲线:
表现力: Kotlin 的革新式语言功能,例如支持类型安全的构建器和委托属性,有助于构建
强大而易于使用的抽象。
可伸缩性: Kotlin 对协程的支持有助于构建服务器端应用程序, 伸缩到适度的硬件要求
以应对大量的客户端。
互操作性: Kotlin 与所有基于 Java 的框架完全兼容,可以让你保持熟悉的技术栈,同时
获得更现代化语言的优势。
迁移: Kotlin 支持大型代码库从 Java 到 Kotlin 逐步迁移。你可以开始用 Kotlin 编写新代
码,同时系统中较旧部分继续用 Java。
工具: 除了很棒的 IDE 支持之外,Kotlin 还为 IntelliJ IDEA Ultimate 的插件提供了框架特
定的工具(例如 Spring)。
学习曲线: 对于 Java 开发人员,Kotlin 入门很容易。包含在 Kotlin 插件中的自动 Java
到 Kotlin 的转换器有助于迈出第一步。Kotlin 心印 通过一系列互动练习提供了语言主要
功能的指南。
服务器推荐的框架
Spring 利用 Kotlin 的语言功能提供更简洁的 API, 从版本 5.0 开始。在线项目生成器允
许用 Kotlin 快速生成一个新项目。
Vert.x 是在 JVM 上构建响应式 Web 应用程序的框架, 为 Kotlin 提供了专门支持,包括
完整的文档。
Ktor 是由 JetBrains 构建的 Kotlin 原生 Web 框架,利用协程实现高可伸缩性,并提供易
于使用且合乎惯用法的 API。
kotlinx.html 是可在 Web 应用程序中用于构建 HTML 的 DSL。 它可以作为传统模板系统
(如JSP和FreeMarker)的替代品。
通过相应 Java 驱动程序进行持久化的可用选项包括直接 JDBC 访问、JPA 以及使用
NoSQL 数据库。 对于 JPA,kotlin-jpa 编译器插件使 Kotlin 编译的类适应框架的要求。
ktor - 用 Kotlin 写的 Web 后端开发框架
Kara - MVC 开发框架
Yested - 用来开发 SPA 应用的框架
HEXAGON- 微服务框架
Android 端
Kotlin 非常适合开发 Android 应用程序,将现代语言的所有优势带入 Android 平台而不会引入
任何新的限制:
兼容性:Kotlin 与 JDK 6 完全兼容,保障了 Kotlin 应用程序可以在较旧的 Android 设备
上运行而无任何问题。Kotlin 工具在 Android Studio 中会完全支持,并且兼容 Android 构
建系统。
性能:由于非常相似的字节码结构,Kotlin 应用程序的运行速度与 Java 类似。 随着
Kotlin 对内联函数的支持,使用 lambda 表达式的代码通常比用 Java 写的代码运行得更
快。
互操作性:Kotlin 可与 Java 进行 100% 的互操作,允许在 Kotlin 应用程序中使用所有现
有的 Android 库 。这包括注解处理,所以数据绑定和 Dagger 也是一样。
占用:Kotlin 具有非常紧凑的运行时库,可以通过使用 ProGuard 进一步减少。 在实际
应用程序中,Kotlin 运行时只增加几百个方法以及 .apk 文件不到 100K 大小。
编译时长:Kotlin 支持高效的增量编译,所以对于清理构建会有额外的开销,增量构建通
常与 Java 一样快或者更快。
学习曲线:对于 Java 开发人员,Kotlin 入门很容易。包含在 Kotlin 插件中的自动 Java
到 Kotlin 的转换器有助于迈出第一步。Kotlin 心印 通过一系列互动练习提供了语言主要
功能的指南。
Android 推荐使用的工具
Kotlin Android 扩展是一个编译器扩展, 可以让你摆脱代码中的 findViewById() 调用,
并将其替换为合成的编译器生成的属性。
Anko 是一个提供围绕 Android API 的 Kotlin 友好的包装器的库,以及一个可以用 Kotlin
Kotlin 用于 Android 代码替换布局 .xml 文件的 DSL。
KAndroid - Kotlin library for Android
Bubble - 屏幕方向监测
Kotpref -android sp缓存工具
Fuese - android内存缓存工具
Kotter Knife KotlinPoet 类似黄油刀的依赖注入框架
Klaxon 一个解析 JSON 的库
Kotlin 与 JavaScript
Kotlin 提供了 JavaScript 作为目标平台的能力。它通过将 Kotlin 转换为 JavaScript 来实现。
目前的实现目标是 ECMAScript 5.1,但也有最终目标为 ECMAScript 2015的计划。
当你选择 JavaScript 目标时,作为项目一部分的任何 Kotlin 代码以及 Kotlin 附带的标准库都
会转换为 JavaScript。 但是,这不包括使用的 JDK 和任何 JVM 或 Java 框架或库。任何不是
Kotlin 的文件会在编译期间忽略掉。
Kotlin 编译器努力遵循以下目标:
提供最佳大小的输出
提供可读的 JavaScript 输出
提供与现有模块系统的互操作性
在标准库中提供相同的功能,无论是 JavaScript 还是 JVM 目标(尽最大可能程度)。
怎么使用kotlin(环境搭建)
IDEA:
Kotlin版本从2015年开始就与IntelliJ IDEA捆绑在一起,
-
在安装IntelliJ IDEA后,打开它并创建一个新项目。选择菜单:【File】->【New Project】,Java Module并选择SDK,Kotlin要与JDK 1.6+一起使用。 另外,选择Kotlin(Java)复选框。
-
点击finish就可以,如下图:
AndroidStudio
好吧,其实IDEA怎么搭建环境不关我什么事,as搭建环境才是关我事情的
-
安装Kotlin的插件:
-
把项目转换为kotlin项目:
-
新建好的MainActivity.java, 注意这里是.java后缀的java文件,我们可以手动转换为kotlin代码
4,转换后得到了一个MainActivity.kt,
到了这一步我们就拿到了一个原汁原味的kotlin项目了。
基本的语法:
基本类型:
数字
定义数字:
var aInt:Int=1
var bDouble:Double=12.5
var fFloat=12.4f
每个数字类型支持如下的转换:
toByte(): Byte
toShort(): Short
toInt(): Int
toLong(): Long
toFloat(): Float
toDouble(): Double
toChar(): Char
也可以有隐式的转换:
val l = 1L + 3 // Long + Int => Long
也支持运算符:
这是完整的位运算列表(只用于 Int 和 Long ):
shl(bits) – 有符号左移 (Java 的 << )
shr(bits) – 有符号右移 (Java 的 >> )
ushr(bits) – 无符号右移 (Java 的 >>> )
and(bits) – 位与
or(bits) – 位或
xor(bits) – 位异或
基本类型
56
inv() – 位非
字符
字符用 Char 类型表示。它们不能直接当作数字
我们可以显式把字符转换为 Int 数字:
fun decimalDigitValue(c: Char): Int {
if (c !in '0'..'9')
throw IllegalArgumentException("Out of range")
return c.toInt() - '0'.toInt() // 显式转换为数字
}
其他的就没什么了.....不讲了
控制流
if else
在 Kotlin 中, if 是一个表达式,即它会返回一个值。 因此就不需要三元运算符(条件 ? 然
后 : 否则),因为普通的 if 就能胜任这个角色。
eg. 有一个int值是a,一个int值是b,求他们的比较大的那个数
java
int a = 1, b = 3;
Log.e("a和b的最大值是", a > b ? a + "" : b + "");
kotlin
val a:Int=1
val b:Int=3
val max = if (a > b) a else b
print("a和b里面最大的是"+max)
When 表达式
when 将它的参数和所有的分支条件顺序比较,直到某个分支满足条件。 when 既可以被当
做表达式使用也可以被当做语句使用。如果它被当做表达式, 符合条件的分支的值就是整个
表达式的值,如果当做语句使用, 则忽略个别分支的值。(像 if 一样,每一个分支可以是
一个代码块,它的值是块中最后的表达式的值。)
如果其他分支都不满足条件将会求值 else 分支。 如果 when 作为一个表达式使用,则必须
有 else 分支, 除非编译器能够检测出所有的可能情况都已经覆盖了。
eg. 实例demo里面的适配器代码:
when (dataItem.type) {
"Android" -> holder?.ivType?.setImageResource(R.mipmap.android_icon)
"iOS" -> holder?.ivType?.setImageResource(R.mipmap.ios_icon)
"前端" -> holder?.ivType?.setImageResource(R.mipmap.js_icon)
"拓展资源" -> holder?.ivType?.setImageResource(R.mipmap.other_icon)
else -> holder?.ivType?.setImageResource(R.mipmap.android_icon)
}
For 循环
for 循环可以对任何提供迭代器(iterator)的对象进行遍历,语法如下:
for (item in collection) print(item)
While 循环
循环中的Break和continue
--- --- 可以参考下我后面发出来的文档
定义一个类:
类声明由类名、类头(指定其类型参数、主构造函数等)和由大括号包围的类体构成。类头
和类体都是可选的; 如果一个类没有类体,可以省略花括号。
class Person constructor(firstName: String) {
}
构造函数
在 Kotlin 中的一个类可以有一个主构造函数和一个或多个次构造函数。主构造函数是类头的
一部分:它跟在类名(和可选的类型参数)后。
class Person constructor(firstName: String) {
}
如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor 关键字。
class Person(firstName: String) {
}
定义一个构造函数的函数体:
class Person(name: String, surname: String) {
init{
...
}
}
很复杂...看懵了,不管了 我们看个例子:
/**
* Created by Ly on 2017/6/23.
*/
open class Person(var age: Int, var name: String) {
fun sayName(): String {
return name
}
fun sayAge(): Int {
return age
}
}
fun main(args: Array<String>) {
val person = Person(11, "Ly")
print(person.sayName()+" is "+person.sayAge())
}
打印结果如下:
修改代码
open class Person(var age: Int, var name: String) {
init {
name="Lht"
age=24
}
fun sayName(): String {
return name
}
fun sayAge(): Int {
return age
}
}
fun main(args: Array<String>) {
val person = Person(11, "Ly")
print(person.sayName()+" is "+person.sayAge())
}
打印结果:
eg. Android 适配器的ViewHolder类(java 代码)
public static class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.iv_girl)
ImageView ivGirl;
public ViewHolder(View itemView) {
super(itemView);
KnifeKit.bind(this, itemView);
}
}
Android适配器的ViewHolder类(Kotlin代码)
inner class GirlHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal var ivGril: ImageView = itemView.findViewById(R.id.iv_girl)
}
Android适配器的ViewHolder类(Kotlin代码 不用缩写 使用init初始化方法)
inner class HomeHolder(item: View) : RecyclerView.ViewHolder(item) {
internal var ivType: ImageView
internal var tvType: TextView
internal var ivAuthor: ImageView
internal var tvAuthor: TextView
internal var tvTime: TextView
internal var rlMessage: RelativeLayout
internal var ivPart: ImageView
internal var ivVedio: ImageView
internal var tvItem: TextView
init {
ivType = itemView.findViewById<ImageView>(R.id.iv_type)
tvType = itemView.findViewById<TextView>(R.id.tv_type)
ivAuthor = itemView.findViewById<ImageView>(R.id.iv_author)
tvAuthor = itemView.findViewById<TextView>(R.id.tv_author)
tvTime = itemView.findViewById<TextView>(R.id.tv_time)
rlMessage = itemView.findViewById<RelativeLayout>(R.id.rl_message)
ivPart = itemView.findViewById<ImageView>(R.id.iv_part)
ivVedio = itemView.findViewById<ImageView>(R.id.iv_vedio)
tvItem = itemView.findViewById<TextView>(R.id.tv_item)
}
}
class的继承:
默认下任何类都是继承自Any( 类似 java中的Object,但是Any 不是 java.lang.Object ;尤其是,它除了 equals() 、 hashCode() 和 toString() 外没有任何成员) ,但是我们可以继承其它类。
所有的类默认都是不可继承的(final),所以我们只能继承那些明确声明open或者abstract的类:
open class Animal(name: String)
class Person(name: String, surname: String) : Animal(name)
当我们只有单个构造器时,我们需要在从父类继承下来的构造器中指定需要的参数。这是用来替换Java中的super调用的。
其实就是super()
字段和属性
类里面有属性,属性可以用关键字 var 声明为可变的,否则使用只读关键字 val
kotlin中的函数:
函数(方法)可以使用fun关键字进行定义:
fun onCreate(savedInstanceState: Bundle?) {
}
如果你没有指定它的返回值,它就会返回Unit,与Java中的void类似,但是Unit是一个真正的对象。你当然也可以指定任何其它的返回类型:
fun add(x: Int, y: Int) : Int {
return x + y
}
然而如果返回的结果可以使用一个表达式计算出来,你可以不使用括号而是使用等号:
fun add(x: Int,y: Int) : Int = x + y
我们可以给参数指定一个默认值使得它们变得可选
fun toast(message: String, length: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, length).show()
}
这个给我的感觉就类似这个:
@RequestMapping(value = "updateType")
public String updateType(
@RequestParam(value = "typeId", defaultValue = "", required = false) Integer typeId,
@RequestParam(value = "typeName", defaultValue = "", required = false) String typeName,
@RequestParam(value = "flag", defaultValue = "1", required = false) Integer flag,
@RequestParam(value = "type", required = false) Integer typeAttributes,
HttpServletRequest request, Model model) {
kotlin中的接口:
android的接口一般用于做回调地狱
interface ItemClickListener {
fun onItemClickListener(url:String)
}
使用点击事件回调地狱
girlAdapter?.setOnItemClickListener(object : GirlAdapter.ItemClickListener {
override fun onItemClickListener(url: String) {
val intent = Intent()
val bun = Bundle()
bun.putString("url", url)
//获取intent对象
intent.setClass(activity, SeeBeautyActivity::class.java)
// 获取class是使用::反射
intent.putExtra("extra", bun)
startActivity(intent)
}
})
kotlin 中的内部类
使用inner关键字
/**
* Created by Ly on 2017/6/23.
* 美女合集适配器
*/
class GirlAdapter(context: Context) : RecyclerView.Adapter<GirlHolder>() {
private var data = ArrayList<GankResults.Item>()
private var context: Context = context
private var onItemClickListener: ItemClickListener? = null
fun setOnItemClickListener(onItemClickListener: ItemClickListener) {
this.onItemClickListener = onItemClickListener
}
fun setData(data: List<GankResults.Item>) {
this.data.clear()
this.data.addAll(data)
notifyDataSetChanged()
}
fun addData(data: List<GankResults.Item>) {
this.data.addAll(data)
notifyDataSetChanged()
}
override fun onBindViewHolder(holder: GirlHolder?, position: Int) {
Glide.with(context).load(data[position].url).into(holder?.ivGirl)
holder?.itemView?.setOnClickListener {
onItemClickListener?.onItemClickListener(data[position].url)
}
}
override fun getItemCount(): Int = data.size
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): GirlHolder {
return GirlHolder(LayoutInflater.from(context).inflate(R.layout.adapter_gril, parent, false))
}
inner class GirlHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
internal var ivGirl: ImageView = itemView.findViewById(R.id.iv_girl)
}
interface ItemClickListener {
fun onItemClickListener(url:String)
}
}
OK 大概了解了kotlin以后,我们进入正题,kotlin与android
划重点:
- 和Java的无缝调用,说明我们使用kotlin代码也可以随意使用目前所有的第三方java语言的sdk
- 大量的语法糖,例如Toast 吐司
- 更加安全,Kotlin 并不存在NullPointException
- RxKotlin
按着两个项目对比讲,主要讲区别 以及anko
OK,开始之前,我们先看两个demo项目:
https://github.com/LinHuanTanLy/JavaDemo
https://github.com/LinHuanTanLy/KotlinDemo