Kotlin初体验

作者: mymdeep | 来源:发表于2017-06-03 14:51 被阅读517次

最近似乎一直在忙,没有抽出时间来写点什么,我也不知道自己在忙什么,但是感觉时间过得好快。这次的文章主要是总结一下最近接触Kotlin的一些实践经历,没有什么太过于复杂深奥的东西,毕竟我也是第一次接触。想了解Kotlin的可以看一下,牛人可以绕行了。


准备工作

我当前使用的AS版本是2.3.x,需要安装Kotlin的相关插件:


下载好插件之后重启AS。
还是新建一个Android 工程,然后对于已经建立好的文件可以使用插件提供的自动转化功能:

  • 选中Java文件->Code->Convert Java File to KotlinFile
  • 转化工程:Tools->Kotlin->Configure Kotlin in Project
    转化完成后的工程样式如下:
    MainActivity
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
 

module下的build.gradle:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"//不做检测会出现问题,找不到库
    // sdk19, sdk21, sdk23 are also available
    // In case you need support-v4 bindings
    // For appcompat-v7 bindings
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    compile 'org.jetbrains.anko:anko-sdk15:0.8.3'
    compile 'org.jetbrains.anko:anko-support-v4:0.8.3'
    compile 'org.jetbrains.anko:anko-appcompat-v7:0.8.3'
    testCompile 'junit:junit:4.12'
}

project下的build.gradle:

buildscript {
    ext.kotlin_version = '1.1.2-4'
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

我下了一个AS3.0版,是可以直接建立Kotlin工程的,2.3版本冒死不行。如果你是使用已有的工程直接转成Kotlin,我的意见是慎重,因为,如果工程过于庞大,很可能出现转化不规范,或者转化错误的地方,到时候很不好检查,可以部分文件部分文件的转化。同时,个人认为,通过java文件转kotlin对比学习,是一个学习Kotlin的好办法

语法

学习一门新的语言的时候,总是要先学习它的语法,对比它的语法与自己已会语言的语法有什么不同。

变量声明

   //空安全变量
        var str: String = "hello"//非空类型
        var str1 = "word"
        //可为空字符串变量
        var str2: String? = null//可空类型 不允许我们直接使用一个可选型的变量去调用方法或者属性。

对于非空类型,如果你将变量设置为空,就会提示错误。
对于可空类型,你是不许调用的它的方法火属性,如val l = str2.length也会报错,但是提供了另外一种方式调用val l = str2?.length ?: -1或者你能确保他是非空的val l1 = str2!!.length两个叹号用来确认变量的非空。
Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?可不做处理返回值为 null或配合?:做空判断处理
还有一种方法更加巧妙:

str2?.let { println("str2"+str2) }

str2后面一定要加?标识可空,let的方法内的执行,只有在str2非空的时候才会去执行。
还有一种写法:

str2?:let {}

把点换成冒号,标识当str2为空的时候才去执行。
以上可以看出Kotlin的用心良苦,这些都完美避免了空指针问题。
顺带说一句吧,拼接字符串跟以前一样,用个加号即可println(str+str1)

switch

when (x) {
    7 -> println("7")//当x为7的时候,输出7
    if (x > 0) 1 else -1 -> println("大于0并等于1,或小于0并等于-1")//如果x>0是1的时候或小于0是-1的时候
    in 1..10 -> println("范围匹配1-10")//是否在1-10之间
    is String -> println("String类型")//是String类型
}

ifelse还是可以正常使用的,所以这里不多介绍,主要介绍一下switch,这个跟以前不太一样了,改用when来代替。
when比switch更加强大,when子式可以是常量、变量、返回数值的表达式、返回Boolean值的表达式,甚至ifelse

ArrayList

fun testArrayList(){
        val list:ArrayList<String> = ArrayList<String>()
        list.add("111")
        list.add("222")
        list.add("333")
        list.add("444")
        list.add("555")
        list.add("666")
        //indices相当于序号集合
        for (i in list.indices) {
            print(list[i]+"  ")

        }
        print("\n")
        for (i in 2..list.size-1) {
            print(list[i]+"  ")

        }
        print("\n")
        for (item in list) {
            print(item+"   ")

        }
        print("\n")
        //加强版
        for ((i,item) in list.withIndex()){
            print(list[i]+"   ")
            print(item+"  |")

        }
        print("\n")
        //变种版
        list.forEach {
            print(it)

        }
      print("\n")
    }

打印效果如下:

06-02 14:06:07.122 20087-20087/com.umeng.soexample I/System.out: 111  222  333  444  555  666  
06-02 14:06:07.122 20087-20087/com.umeng.soexample I/System.out: 333  444  555  666  
06-02 14:06:07.122 20087-20087/com.umeng.soexample I/System.out: 111   222   333   444   555   666   
06-02 14:06:07.123 20087-20087/com.umeng.soexample I/System.out: 111   111  |222   222  |333   333  |444   444  |555   555  |666   666  |
06-02 14:06:07.123 20087-20087/com.umeng.soexample I/System.out: 111222333444555666

类的相关特性

构造函数

class Person (private val name: String,private val age: String) {
    fun sayHello() {
        println("$name is $age years old")
    }
}

Kotlin允许将构造参数直接跟在类名后面,这种写法声明的构造函数,我们称之为主构造函数。
这时可能有人会有疑问,如果希望在构造函数中添加一些代码逻辑怎么实现?

class Person (private val name: String,private val age: String) {


    init {
        println("$name init")
        println("$age init")
    }
    fun sayHello() {
        println("$name is $age years old")
    }
}

刚才提到了这是主构造函数,有主就有次,那么一定有次级构造函数。次级构造函数就需要写在类中了:

class Person (private val name: String,private val age: String) {

    private var sex: String? = null
    init {
        println("$name init")
        println("$age init")
    }
    constructor(name: String, age: String,sex: String) : this(name,age) {
            this.sex = sex
    }
    internal fun sayHello() {
        println("$name is $age years old")
    }
}

我们让次级构造函数调用了主构造函数。由于次级构造函数不能直接将参数转换为字段,所以需要手动声明一个 sex 字段,并为 sex 字段赋值。
在字符串内部调用$符号,标识后面的是变量,将会把变量的内容替换到该位置。

这里要说一下internal是含义,在同一个module中,它相当于public,在module之外,相对于private

类的扩展

Kotlin可以在已有类中添加新的方法, 比继承更加简洁和优雅。
我们可以在Activity中写一个这样的方法:

   fun Person.toast() {

        var userInfo = "name:$name,  age:$age"

        println(userInfo)
    }

为什么这么写呢,这个方法不是Activity类内的方法,实际它是刚才Person类的方法,我们调用一下:

  val person = Person("deep","30","man")
   person.toast();

结果如下:

06-02 17:25:54.095 3989-3989/com.umeng.soexample I/System.out: deep init
06-02 17:25:54.095 3989-3989/com.umeng.soexample I/System.out: 30 init
06-02 17:25:54.095 3989-3989/com.umeng.soexample I/System.out: name:deep,  age:30

转换

之前也提到过,可以用 is 来判断一个对象是否是某个类的实例,但是如果需要强制转化呢,我们可以使用as

  (person as Person).sayHello()

伴生对象

Kotlin之所以这么做,是由于Kotlin 没有静态方法。在大多数情况下,官方建议是简单地使用伴生对象。

public final class StringUtils public constructor() {
    public companion object {
        public final fun getLength(str: kotlin.String): Int {
           return str.length;
        }
    }
}

我们可以这样调用:

 StringUtils.getLength("1111111");

我们可以看出这种用法相当于静态方法。
所以,我们也可以用这种方式来处理单例模式的类:

class SingleObject private constructor() {
    companion object {
        fun get():SingleObject{
            return Holder.instance
        }
    }

    private object Holder {
        val instance = SingleObject()
    }
}

然后用SingleObject.get();进行调用
要注意private constructor()这种写法,把构造函数私有化。

布局

如果以之前的思路使用xml,布局文件,那么将Activity中的代码,转成Kotlin,应该是如下的样子

class LayoutActivity : Activity() {
    internal var btn1: Button? = null;
    internal var btn2:  Button? = null;
    internal var btn3:  Button? = null;
    internal var btn4:  Button? = null;
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_layout)
        btn1 = findViewById(R.id.btn1) as Button
        btn2 = findViewById(R.id.btn2) as Button
        btn3 = findViewById(R.id.btn3) as Button
        btn4 = findViewById(R.id.btn4) as Button
        btn1!!.setOnClickListener { Toast.makeText(this@LayoutActivity, "1111", Toast.LENGTH_LONG).show() }
        btn3!!.setOnClickListener { Toast.makeText(this@LayoutActivity, "333333", Toast.LENGTH_LONG).show() }
        btn2!!.setOnClickListener { Toast.makeText(this@LayoutActivity, "222222", Toast.LENGTH_LONG).show() }
        btn4!!.setOnClickListener { Toast.makeText(this@LayoutActivity, "444444", Toast.LENGTH_LONG).show() }

    }
}

在这里推荐另外一种方式布局,就是不使用布局文件。
这种方式需要额外依赖一些库:

    compile 'org.jetbrains.anko:anko-sdk15:0.8.3'
    compile 'org.jetbrains.anko:anko-support-v4:0.8.3'
    compile 'org.jetbrains.anko:anko-appcompat-v7:0.8.3'

我们来看一下写法:

class AnkoActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        relativeLayout {
            val tv = textView("aaaaa") {
                textSize = 25f
            }.lparams {
                width = matchParent
                alignParentTop()
            }

            button("Sample button").lparams {
                width = matchParent
                alignParentBottom()
            }
            textView("bbbbb").lparams {
                below(tv)
                alignParentRight()
                topMargin = 400
            }
        }
    }
}

这种设置方式与布局文件类似,所有能在布局文件中设置的,在这里也能设置,也是使用的嵌套的方式。
这种方式不做过多解释,觉得喜欢的朋友可以查看Anko的相关用法。

总结

Kotlin的学习成本并不高,而且可以通过这个AS的插件,将现有java文件逐个转化进行学习。如果能够熟练掌握Kotlin,确实从代码量上能节省很多。
有疑问的朋友欢迎给我留言指正,或者关注我的公众号留言:


相关文章

  • kotlin小白日记2「工具类的封装,Anko简化吐司,空值处理

    Kotlin初体验二「kotlin框架Anko的使用,工具类的封装,空值处理」 本篇上篇为kotlin初体验,源代...

  • Kotlin 初体验

    Kotlin 初体验 Kotlin也是基于JVM设计的编程语言,相对Java来说,Kotlin在编写代码时有如下优...

  • 使用Kotlin开发Android应用初体验

    使用Kotlin开发Android应用初体验 昨晚,最近一届的谷歌IO大会正式将Kotlin确定为了官方开发语言,...

  • 《Kotlin 实战》 读书笔记——第一章

    1.1 Kotlin初体验 从小例子开始看看Kotlin代码长什么样子。下面这个例子,定义了一个Person类来表...

  • 初识Kotlin

    kotlin到底是什么? 开发工具: kotlin初体验 上述代码的含义: 你声明了一个简单的数据类,它包括了两个...

  • Kotlin初体验

    距离kotlin成为Android一级开发语言已经一年了,这节将从零开始,实现kotlin的几个小知识点,以下操作...

  • Kotlin初体验

    开发工具: IntelliJIDEA 第一步:打开idea IDE 选中 kotlin 点击next选项 第...

  • Kotlin初体验

    谷歌大会之后,Kotlin火的不要不要的,将来用Kotlin开发Android应用或许会成为主 流,所以An...

  • Kotlin初体验

    项目环境 android studio 2.2.2 首先安装 Kotlin插件 然后重新启动 Android St...

  • kotlin初体验

    前言 之前呢一直听说kotlin怎么怎么厉害,但是我那会觉得java现在覆盖率这么高。如果要替代可能还要很久呢,也...

网友评论

    本文标题:Kotlin初体验

    本文链接:https://www.haomeiwen.com/subject/nanyfxtx.html