使用 Kotlin 创建掘金首页

稀土技术分享会

作者:NeXT___

新建 Android Studio 工程的目录结构
.
├── app                 // 应用源代码
    ├── ...
    ├── build.gradle    // 应用 Gradle 构建脚本
    ├── ...
├── build.gradle        // 项目 Gradle 构建脚本
├── YOUR-APP-NAME.iml   // YOUR-APP-NAME 为你的应用名称
├── gradle
└── settings.gradle

AndroidStudio

Kotlin

Kotlin 是一门与 Swift 类似的静态类型 JVM 语言,由 JetBrains 设计开发并开源。与 Java 相比,Kotlin 的语法更简洁、更具表达性,而且提供了更多的特性。它与 Java 高度可互操作,可以同时用在一个项目中。


AndroidStudio
http://developer.android.com/intl/zh-cn/sdk/index.html
http://stormzhang.com/devtools/2014/11/25/android-studio-tutorial1/

配置
http://www.kymjs.com/code/2015/07/22/01

在线学习:
http://try.kotlinlang.org/#/Examples/Delegated%20properties/NotNull%20property/NotNull%20property.kt

构造函数
https://kotlinlang.org/docs/reference/classes.html

Kotlin Android Extensions
https://github.com/wangjiegulu/kotlin-for-android-developers-zh/blob/master/zen_yaoqu_shi_yong_kotlinandroid_extensions.md

anko 高级功能
http://kingideayou.github.io/2016/04/23/advanced_features_of_Anko/

《Kotlin for android developers》中文版翻译
https://wangjiegulu.gitbooks.io/kotlin-for-android-developers-zh/content/

Demo 地址:
    Java 版:  https://github.com/kingideayou/GoldDemoProject
    Kotlin 版:https://github.com/kingideayou/GoldKotlinDemoProject

变量可以分为可变(var)和不可变(val)的变量

//java
Int a = 1;
String b = "";


//kotlin
val i = 12 // An Int
val iHex = 0x0f // 一个十六进制的Int类型
val l = 3L // A Long
val d = 3.5 // A Double
val f = 3.5F // A Float


一个String可以像数组那样访问,并且被迭代:
val s = "Example"
val c = s[2] // 这是一个字符'a'
// 迭代String
val s = "Example"
for(c in s){
    print(c)
}

变量

类和函数

//类
//定义一个类
class MainActivity{
}

//默认构造器
class Persion(name: String, age: Int) {}

//类继承
open class Animal(name: String)
class Person(name: String, type: String) : Animal(name)




//函数
//使用 fun 关键字
fun onCreate(savedInstanceState: Bundle?) {
}

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()
}

toast("Hello World")
toast("Hello World", Toast.LENGH_LONG)

copy 对象



LeaderBoard lb1 = new LeaderBoard("hanks", "99", "稀土", "Android 工程师");
LeaderBoard lb = new LeaderBoard(lb, "TYPE_EDITOR");


public LeaderBoard(String username, int rankIndex, String jobTitle, String company {
        this.rankIndex = rankIndex;
        this.username = username;
        this.jobTitle = jobTitle;
        this.company = company;
    }

public LeaderBoard(LeaderBoard leaderBoard, String type) {
        this.type = type;
        this.ranking = leaderBoard.ranking;
        this.username = leaderBoard.username;
        this.jobTitle = leaderBoard.jobTitle;
        this.company = leaderBoard.company;
    }

Kotlin copy 对象


    val user = User("Alex", 1)
    println(user) // toString()

    val secondUser = User("Alex", 1)
    val thirdUser = User("Max", 2)

    println("user == secondUser: ${user == secondUser}")
    println("user == thirdUser: ${user == thirdUser}")

    // copy() function
    println(user.copy())
    println(user.copy("Max"))
    println(user.copy(id = 2))
    println(user.copy("Max", 2))

With 函数


//before
class MyViewHolder(itemView: View, val itemClick: (Entry) -> Unit) : RecyclerView.ViewHolder(itemView) {
    
    val tvTitle = itemView.find(R.id.tv_title)
    val tvRank = itemView.find(R.id.tv_rank)
    
    fun bindViewHolder(leaderBoard: LeaderBoard) {
            tvTitle.setText(leaderBorad.userName)
            tvRank.setText(leaderBoard.rank)
    }   
}

//after
class MyViewHolder(itemView: View, val itemClick: (Entry) -> Unit) : RecyclerView.ViewHolder(itemView) {
    
    val tvTitle = itemView.find(R.id.tv_title)
    val tvRank = itemView.find(R.id.tv_rank)

    fun bindViewHolder(leaderBoard: LeaderBoard) {
        with(leaderBoard) {
            tvTitle.setText(userName)
            tvRank.setText(rank)
        }
    }
}
//需要 import kotlinx.android.synthetic.main.view_item.view.*

//before
class MyViewHolder(itemView: View, val itemClick: (Entry) -> Unit) : RecyclerView.ViewHolder(itemView) {
    
    val tvTitle = itemView.find(R.id.tvTitle)
    val tvRank = itemView.find(R.id.tvRank)

    fun bindViewHolder(leaderBoard: LeaderBoard) {
        with(leaderBoard) {
            tvTitle.setText(userName)
            tvRank.setText(rank)
        }
    }
}

//after
class MyViewHolder(itemView: View, val itemClick: (Entry) -> Unit) : RecyclerView.ViewHolder(itemView) {
    fun bindViewHolder(leaderBoard: LeaderBoard) {
        with(leaderBoard) {
            itemView.tvTitle.setText(userName)
            itemView.tvRank.setText(rank)
        }
    }
}

Lambdas 表达式


public interface OnClickListener {
    void onClick(View v);
}

//java 匿名内部类实现接口
view.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {
        Toast.makeText(v.getContext(), "Click", Toast.LENGTH_SHORT).show();
    }
})

//Kotlin
view.setOnClickListener(object : OnClickListener {
    override fun onClick(v: View) {
        toast("Click") //anko
    }
}

//Kotlin Interface 中包含单个函数可以被替代为一个函数。
fun setOnClickListener(listener: (View) -> Unit)
//lambda表达式通过参数的形式被定义在箭头的左边(被圆括号包围),然后在箭头的右边返回结果值。我们接收一个View,然后返回一个Unit
view.setOnClickListener({ view -> toast("Click")})
//箭头的左边指定参数,箭头的右边返回函数执行的结果。可以省略未用到的参数:
view.setOnClickListener({ toast("Click") })
//函数的最后一个参数是一个函数,可以把函数移到圆括号外面:
view.setOnClickListener() { toast("Click") }
//如果这个函数只有一个参数,可以省略圆括号:
view.setOnClickListener { toast("Click") }

//如果这个函数只接收一个参数,可以使用 it 引用
view.setOnClickListener { user -> toast(user.userName) }
view.setOnClickListener { toast(it.userName) }

Title Text

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' //Kotlin 插件
android {
    compileSdkVersion 23
    buildToolsVersion "24.0.0 rc2"
    defaultConfig {
        ...
    }
    buildTypes {
        release {
            ...
        }
    }
    sourceSets { main.java.srcDirs += 'src/main/kotlin'}
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" //kotlin
}
buildscript {
    ext.kotlin_version = '1.0.1-2' //kotlin
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}
repositories {
    mavenCentral()
}

app/bulid.gradle

Kotlin Android Extensions 

创建 Kotlin 项目时,已经在 build.gradle 文件中添加了依赖:

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }

使用时需要我们手动 import 

1. Acitivties 或者 Fragment 

在 Activity 中,需 import 以 kotlinx.android.synthetic 为开头的,然后加上布局文件 xml 的名字:
    
    import kotlinx.android.synthetic.activity_main.*

同时注意,在 Activity 布局中 include 的布局,也需要手动 import
    
    import kotlinx.android.synthetic.activity_main.*
    import kotlinx.android.synthetic.content_main.*

导入之后,会自动生成与布局文件中对应 id 相同的属性名

2. Views

绑定一个 xml 中的 view 到另一个 view
    
    import kotlinx.android.synthetic.view_item.view.*

使用
    view.textview.text = "Hello World"

Made with Slides.com