Android必备技能之一:Kotlin(一)

20161105_161848.jpg

1、Kotlin前世与今生

  • 写了太久Java,有没有发现其实你写了太多冗余的代码?
  • 你虽然小心翼翼,可总是被QA折腾出来的NullPointerException所头疼,难道就没有受够这种日子么?
  • 直到有一天你发现自己代码除了if,else,for循环,竟然没有任何留恋?

那么我们可以一起来尝试一下 Kotlin,话说回来了什么是Kotlin呢?

Kotlin是基于JVM新的编程语言,由 JetBrains 开发,可以编译成java字节码,也可以编译成JavaScript。而JetBrains,作为目前广受欢迎的Java IDE IntelliJ 的提供商,也在 Apache 许可下已经开源其Kotlin 编程语言。

2、Kotlin环境配置

接下来的我就直接在Android Studio(下面简称AS)环境上面操作,虽然使用IDE IntelliJ也可以实现,但AS上也是对Kotlin支持的,首先下载以下相关插件(虽然并不是所有插件一次性用到,但建议一次性下载完,后续就不需要下载了):

  • Kotlin
  • Kotlin Extensions For Android
  • Anko DSL Preview

其中Anko DSL Preview插件用于预览使用DSL编写的UI代码,就像以前使用xml编写UI文件时可以动态在“Preview”窗口预览效果一样。

上面三个插件下载安装重启之后,然后新建一个项目默认配置Gradle如下:

    ext.kotlin_version = '1.1.0'
    ext.anko_version = '0.8.2'
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
    }
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

.........................

dependencies {
    .........................
    
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
    compile "org.jetbrains.anko:anko-sdk15:$anko_version"
    compile "org.jetbrains.anko:anko-support-v4:$anko_version"
    .........................
}
repositories {
    mavenCentral()
}

这里添加了Kotlin对android的扩展,同时也添加了Kotlin的gradle插件。我们打开系统默认帮我们建的MainActivity,然后Code->Convert Java File to Kotlin File->OK,此时我们原有的Activity应该将我们转换成了如下内容:

class KoTlinActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_ko_tlin)
    }
}

上面这一步是将java代码转换为Kotlin代码。截止到现在,你什么都不用做,程序就已经可以跑起来了。你可能要说代码相比之下并没有简洁多少啊 ,当然到这里并没有结束,反而是开始,只是首先一起来体验下我们的第一个Kotlin代码程序。

3、Kotlin完美给Java开发者打造

3.1 通用的集合框架和Kotlin的扩展

通用的集合框架,ex如下:

  val list = arrayListOf(1, 2, 3, 4)
        list.add(5)
        list.remove(3)
        for (item in list) {
            debug(item);
        }

效果如下:

03-09 16:06:23.991 21108-21108/com.Igeek.kotlin D/MainActivity: 1
03-09 16:06:23.991 21108-21108/com.Igeek.kotlin D/MainActivity: 2
03-09 16:06:23.991 21108-21108/com.Igeek.kotlin D/MainActivity: 4
03-09 16:06:23.991 21108-21108/com.Igeek.kotlin D/MainActivity: 5

可以看到这里Kotlin写法和java是差不多的。

至于Kotlin的扩展,其实就是对java的库进行了进一步扩展,ex如下:

 val list = arrayListOf(1, 2, 3, 4, 5)
        list.forEach {
            debug(it)
        }
        debug("==========================")
        val doubleList = list.map {
            it * 2
        }
        doubleList.forEach {
            debug(it)
        }
        debug("==========================")
        val oddList = list.filter{
            it % 2 == 1
        }
        oddList.forEach {
            debug(it)
        }

打印如下:

03-09 16:18:06.978 28828-28828/com.Igeek.kotlin D/MainActivity: 1
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 2
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 3
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 4
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 5
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: ==========================
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 2
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 4
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 6
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 8
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 10
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: ==========================
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 1
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 3
03-09 16:18:06.979 28828-28828/com.Igeek.kotlin D/MainActivity: 5

3.1 Kotlin与Java的交互

Kotlin的标准库更多的是对Java库的扩展,基于这个设计思路,你丝毫不需要担心Kotlin对Java代码的引用,你甚至可以在Kotlin当中使用Java反射,反正只要是Java有的,Kotlin都有。最常见的就是Getter/Setter方法对应到Kotlin属性的调用,ex如下:
首先准备一个java类:

8208E5B2-6AA0-4F0F-BA2D-A1F067D08DCC.png

调用如下:

       val javaPerson = Person()
        javaPerson.address = "Wo shi Kotlin"
        debug(javaPerson.address)

打印结果就是"Wo shi Kotlin"了,刚刚只顾着写,忘了提一句,在Kotlin语法里面,是不用在后面加“;”的,有没有感觉很爽,废话不说了,可以看到我们调用时候,既没有用到get方法也没有用到set方法,是不是避免了总会有人说get/set方法影响性能的问题。
官网地址(有详细的比较):https://kotlinlang.org/docs/reference/java-interop.html#static-methods-and-fields

4、简洁 可靠 有趣

4.1数据类

在JavaBean中我们往往会覆写诸如equals和hashcode等方法,一旦用到HashMap这样的集合框架,总是出了问题都不知道找谁。Kotlin提供了一种非常简单的方式来创建这样的数据类,ex如下:

data class Main(val id:Int,val name:String)

//main方法调用
fun main(args:Array<out String>){
    println(Main(0,"Main函数"))
}

打印结果:

Main(id=0, name=Main函数)

仅仅一行代码,Kotlin就会创建出一个完整的数据类,并自动生成相应的equals、hashcode、toString方法。

4.2 空安全与属性代理

想想平时QA提的bug,不太靠谱的server,不太确定数据类型,均可能出现Exception,但我们总不能在所有地方都进行判断,第一次看到Kotlin的空安全处理,真的眼前一亮。
Kotlin的空安全设计,主要是在类型后面加?表示可空,否则就不能为null,ex如下:

val nullable: Int? = 0
val nonNullable: Int = 2
nullable.toFloat() // 编译错误
nullable?.toFloat() // 如果null,什么都不做,否则调用toFloat
nullable!!.toFloat() // 强制转换为非空对象,并调用toFloat;如果nullable为null,抛空指针异常
nonNullable.toFloat() // 正确

我们利用Convert Java File to Kotlin File生成的Kotlin代码,在onCreate方法中也是如此考虑,savedInstanceState是否为空。

override fun onCreate(savedInstanceState: Bundle?) {}

注:这里的空指针异常是KotlinNullPointerException,而不是Java的NullPointerException。

5、Kotlin场景使用

好了,接下来我们就实战说说Kotlin的用法,用如下代码举例:
java代码:

8F167006-EA0F-4D14-BE9B-20BA6562DDEA.png

Kotlin代码:

46EA6401-2A70-40FA-91A5-9EAA38E76670.png

5.1 场景一(控件findViewById)

findViewById有很多写法,我们就从复杂到容易说起:

写法一:

      private var tv_hello_view: TextView? = null
         .......................................
        tv_hello_view = findViewById(R.id.tv_hello_view) as TextView
        tv_hello_view!!.text = "Say Hello!!!"
        tv_hello_view!!.textSize = 22f
        tv_hello_view!!.setOnClickListener {}

有没有发现写法一还不如java写法,貌似java写法还简单一点,并且设置text和size时候,需要加两个叹号,不加的话貌似编译器并不识别你是否为null,下面我们来看写法二:

写法二:

   private val  tv_hello_view: TextView by lazy{
        findViewById(R.id.tv_hello_view) as TextView
    }
   .......................................
        tv_hello_view.text = "Say Hello!!!"
        tv_hello_view.textSize = 22f
        tv_hello_view.setOnClickListener {}

这种写法好像简单了一点,不过好像依然很复杂,注意在这里初始化的时候不要直接

private var tv_hello_view: TextView  //编译错误

lazy是Kotlin的属性代理的一个实例,它提供了延迟加载的机制。换句话说,这里的lazy提供了初始化aTextView的方法,不过真正初始化这个动作发生的时机却是在aTextView第一次被使用时了。lazy默认是线程安全的,你当然也可以关掉这个配置,只需要加个参数LazyThreadSafetyMode.NONE即可:

private val tv_hello_view: TextView by lazy(LazyThreadSafetyMode.NONE){
     findViewById(R.id.tv_hello_view) as TextView
}

写法三:

private lateinit var tv_hello_view: TextView
   .......................................
        tv_hello_view = findViewById(R.id.tv_hello_view) as TextView
        tv_hello_view.text = "Say Hello!!!"
        tv_hello_view.textSize = 22f
        tv_hello_view.setOnClickListener {}

这里主要用了lateinit 来修饰它,方法简单了不少吧 ,但是findViewById这个单词好长啊,能不能简化啊,答案是肯定的,我们请出Anko,注意我们有依赖过dependencies哟。

写法四:

private lateinit var tv_hello_view: TextView
   .......................................
        tv_hello_view = find(R.id.tv_hello_view) 
        tv_hello_view.text = "Say Hello!!!"
        tv_hello_view.textSize = 22f
        tv_hello_view.setOnClickListener {}

可以看到我们方法改成了find,并且没了 as TextView,注意我们需要import org.jetbrains.anko.find。既然请出来了Anko ,那么我们还有终极方案,完全去除findViewById。

写法五:

CD9648CF-79D0-48FB-AED7-59A2CAAF448B.png

可以发现直接操作tv_hello_view,这便是findViewById的终极写法。
注:

1.导入了import kotlinx.android.synthetic.main.hello_layout.*包
2. tv_hello_view是hello_layout布局xml中的id

写到这里,内容也挺多了,我也只是把用法统一归纳一下,至于findViewById所牵扯出来的几个点:lazy,primitives, lateinit, Anko以及不要 findViewById仍然能找到控件的原理我并没有去细致分析,后续有时间我会再补充上,当然如果想更多的去了解,可以有一下资料参考:

Kotlin官网文档地址:https://kotlinlang.org/docs/
《Kotlin for android Developers》中文翻译: https://github.com/wangjiegulu/kotlin-for-android-developers-zh/blob/master/SUMMARY.md

在这里推荐一部Kotlin基础学习视频:https://pan.baidu.com/s/1b2tBH0 提取码:nryk

本博客参考了一下文献:
Kotlin for android Developers》中文翻译;
博客:http://www.println.net/post/Android-A-Powerful-Substitution-Kotlin
博客:http://mp.weixin.qq.com/s?__biz=MzIzMTYzOTYzNA==&mid=100000121&idx=1&sn=6a8c4b27dec4e03a58e888c5fa18b7e2&chksm=68a05e445fd7d752da50717bec037f51702aa9557b308114f2d7255109509bcd24c1a5d80903&mpshare=1&scene=23&srcid=0309PegdxPNifENVckrvhBZY#rd

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

推荐阅读更多精彩内容