美文网首页kotlin频道Kotlin开发知识Kotlin学习
Android必备技能之一:Kotlin(一)

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

作者: 罗罗罗罗罗sky | 来源:发表于2017-03-10 09:29 被阅读1129次
    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

    相关文章

      网友评论

      • Hancock1993:请问 tv_hello_view 变成红色字体, 改的是颜色主题里面那个具体的选项啊?
      • 艾伦oy:写的不错,入门必备干货

      本文标题:Android必备技能之一:Kotlin(一)

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