Kotlin for Android

邓琴文

最近在学习kotlin语法,有一本书《kotlin for Android developers》对kotlin语法有很详细的讲解,但是我决定写一篇快速在Android开发中感受Kotlin奇妙的文章。


首先创建一个基本的demo

在plugins里面添加kotlin插件,在build.gradle里面加入下面这几个配置

apply plugin: 'kotlin-android'  
apply plugin: 'kotlin-android-extensions'  
apply plugin: 'kotlin-kapt'

dependencies {  
    "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

把activity页面转成kotlin页面,打开文件,选择code -> convert file to kotlin file ,然后就会把java代码转成kotlin代码了。 看一下demo的基本代码和运行结果: - activity代码 image

  • xml文件 image

  • demo效果 image


kotlin与java语法对比

View Binding

看上面的demo代码我们发现了kotlin的一个特别方便的地方,没有findViewById() 这个方法了。对于Android开发人员来说,findViewById() 这个方法真的是太熟悉了,因为太熟悉所以也知道这个方法带来的问题也很让人头痛,尽管存在一系列的开源库能够为这个问题带来解决方案,但是和kotlin一对比真的还是差太多了。

现在 Kotlin 安卓扩展插件能够提供与这些开源库功能相同的体验,只需要在build.gradle里面启用 Gradle 安卓扩展插件就可以了

apply plugin: 'kotlin-android-extensions'  

就是这个东西,其他的不需要添加任何额外代码。

使用的时候我们直接用View的id就可以去使用View的基本属性。系统会自动给我们导入

import kotlinx.android.synthetic.main.<布局名>.*  

当前demo的布局名是activity_kotlin,所以导入的是

import kotlinx.android.synthetic.main.activity_kotlin.*  

之后就可以非常简单快捷的设置View的属性了,比如:

text_view.text = "hello world";  
text_view.visibility= View.GONE;  

虽然现在我们骑手项目里面用的开源库简化findViewById(),但是对于一个页面布局有很多View的来说,声明布局View的名称还是非常繁琐的。比如下图这样的还只是所有的1/3,如果使用kotlin这些声明都可以去掉,直接用View的id就可以去使用了。

image

函数定义

  • 无返回值的函数(类似Java中的void)
fun log(a:Int,b:Int){  
    Log.d("log",a);
}
// 等同于是返回 Unit类型,则可以省略
fun log(a:Int,b:Int):Unit{  
    Log.d("log",a);
 }
  • 有返回值的函数
//参数是Int类型,返回值是Int类型
fun add(a:Int,b:Int):Int{  
    return a+b
}
//理解为简写吧,由系统自动判断返回类型
 fun add(a:Int,b:Int)=a+b 
  • kotlin中的构造方法和函数参数 从上面可以看出,kotlin中我们可以先写参数名字再定义它的类型,所以我们可以给参数指定一个默认值使这个参数变得可选,比如:
fun toast(message:String,length:Int = Toast.LENGTH_SHORT){  
    Toast.makeText(this,message,length).show();
}

第二个参数我们是给了一个默认值的,所以第二个参数就可以不传,所以我们调用的时候可以有两种调用方法:

toast("hello World",Toast.LENGTH_LONG);  
toast("hello world");  

这样一个函数就能实现java里面的重载函数,与下面的java代码是一样的,用起来还是非常方便的:

public void toast(String message){  
    Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
}

public void toast(String message,int length){  
    Toast.makeText(this,message,length).show();
}

当然还有静态函数,在Kotlin里边被叫做了:伴生对象,至于这个半生对象的名词解释呢,要了解的人直接去查吧,我们直接看代码:

class function {

    companion object {
        fun delete(){
            Log.d("function","delete");
        }
    }
}

//调用呢就是下面这样
function.delete();  

这只是kotlin函数的最基本的一些用法,还有许多实现细节可以去参考书籍。总的来说基本的一些用法理解上还是比较简单的,给人的感觉也是很干净的代码。

kotlin in Adapter

Android 中用的最多的列表控件的Adapter用法,在kotlin中是怎样的呢,先看代码

@Suppress("UNUSED_EXPRESSION")
class TestAdapter(var items: List<String>) : RecyclerView.Adapter<TestAdapter.ViewHolder>() {  
    override fun getItemCount(): Int {
        return items.size;
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(TextView(parent.context));
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.textView.text=items[position];
    }


    class ViewHolder(var textView: TextView) : RecyclerView.ViewHolder(textView)
}

在最开始声明这个class的时候,我们直接在TestAdapter的主构造方法中声明了一个var的变量。这种写法就类似于Java中的:

class TestAdapter {  
    public List<String> items;

    public TestAdapter(List<String> data){
        this.items = data;
    }
}

从上面我们可以看出kotlin的类的声明方式,在声明类的时候直接在后面加入需要的参数,如果这个类不需要参数传入,就可以不要();

在kotlin的Adapter中,ViewHolder 也变的很简单了

class ViewHolder(var textView: TextView) : RecyclerView.ViewHolder(textView)  

看一下java代码:

public class ViewHolder extends RecyclerView.ViewHolder {  
    public TextView textView;

    public viewHolder(TextView textView){
        super(textView);
        this.textView = textView;
    }
}

这个就是把主构造方View,传给RecyclerView.ViewHolder()构造方法中,和我们的Java代码一样的,就是刚开始看的时候理解上有点难而已。

但是我在写demo的时候就发现了一些注意事项,在声明类的时候传入的参数可以用var定义,也可以不用var定义,但是这两个有很大的区别。

用var定义的参数,可以在类中的所有方法里面直接调用,类似于java中的全局变量,不用var定义的参数,就只能在构造方法体里面用,类似于java的局部变量,

  • 当我们不用var定义参数时,使用这个参数时会找不到报错,如下

image

  • 用var定义时是可以直接使用的。

image

那我们不用var定义参数,这个参数我们要使用怎么办呢,看代码:

class Name(name: String) {

    var myName: String ? = null;

    init {
        this.myName = name;
    }

    fun yourName(): String ? {
        return myName;
    }
}

就是这样我们像java里面一样声明一个全局变量,在init块里把传入的name变量赋值给我们定义的myName就可以了。init块就是kotlin中类的构造函数的函数体,构造函数中的代码处理都放在init块中实现。

上面有一行 var myName: String ? = null; 这个代码,这个涉及到了kotlin中的null安全,据说可以完美的避免NullPointerException,具体的还没有学习,就先不说了。

小结

有java语法的基础,理解kotlin的语法还是比较容易的。但是任何一门语言肯定不只是简单的理解,在使用中才能发现其精髓。目前我也只是结合Android开发中常用的东西去粗略的学了一些kotlin的基本的语法,Kotlin也是谷歌官方推荐的Android开发语言了,虽然我们的项目现在还没有用到,但是我们也可以在这之后慢慢的加入kotlin的大军。有学习kotlin语法的小伙伴也可以一起讨论交流。

参考书籍

《kotlin for android developers》