介绍Kotlin
- 编写代码量少
- 更加安全:Kotlin编译时期就处理了各种null的情况,避免了执行时异常。如果一个对象可以是null,则我们需要明确地指定它,然后在使用它之前检查它是否是null
- 它是函数式的:Kotlin是基于面向对象的语言,它使用了很多函数式编程的概念,比如,使用lambda表达式来更方便地解决问题。其中一个很棒的特性就是Collections的处理方式
- 它可以扩展函数:可以扩展类的更多的特性,甚至我们没有权限去访问这个类中的代码
- 它是高度互操作性的:你可以继续使用所有的你用Java写的代码和库,因为两个语言之间的互操作性是完美的。可以在一个项目中使用Kotlin和Java两种语言混合编程
特性
Expresiveness 可读性
- POJO - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- public class Artist { 
 private long id;
 private String name;
 private String url;
 private String mbid;
 public long getId() {
 return id;
 }
 public void setId(long id) {
 this.id = id;
 }
 ···
- Kotlin中创建数据类Artist.kt,自动生成所有属性和访问器 - 1 - data class Artist(var id: Long, var name: String, var url: String, var mbid: String) 
空安全
| 1 | //编译不通过,非空类不能为null | 
扩展方法
| 1 | val fragment= Fragment() | 
Lambda
| 1 | textView.setOnClickListener { toast("Kotlin") } | 
创建一个项目
- Project/build.gradle - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27- buildscript { 
 ext.kotlin_version = '1.2.30'
 ext.support_version = '26.1.0'
 ext.anko_version = '0.10.4'
 repositories {
 google()
 jcenter()
 }
 dependencies {
 classpath 'com.android.tools.build:gradle:3.0.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 {
 google()
 jcenter()
 }
 }
 task clean(type: Delete) {
 delete rootProject.buildDir
 }
- app/build.gradle - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39- apply plugin: 'com.android.application' 
 apply plugin: 'kotlin-android'
 apply plugin: 'kotlin-android-extensions'
 android {
 compileSdkVersion 26
 defaultConfig {
 applicationId "com.willkernel.app.kotlindemo"
 minSdkVersion 23
 targetSdkVersion 26
 versionCode 1
 versionName "1.0"
 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
 }
 buildTypes {
 release {
 minifyEnabled false
 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
 }
 }
 
 androidExtensions {
 experimental = true
 }
 }
 dependencies {
 implementation fileTree(dir: 'libs', include: ['*.jar'])
 implementation 'com.android.support:appcompat-v7:26.1.0'
 implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
 implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
 implementation "org.jetbrains.anko:anko-common:$anko_version"
 implementation "org.jetbrains.anko:anko-sqlite:$anko_version"
 implementation "org.jetbrains.anko:anko-coroutines:$anko_version"
 implementation 'com.android.support.constraint:constraint-layout:1.0.2'
 testImplementation 'junit:junit:4.12'
 androidTestImplementation 'com.android.support.test:runner:1.0.1'
 androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
 }
- 转换java到kotlin  
- 导入布局属性 - import kotlinx.android.synthetic.main.activity_main.*- 1 
 2- textView.setText(R.string.app_name) 
 textView.text = getString(R.string.app_name)
- 定义类,有一个默认唯一的构造器,如果没有方法,只要名称,变量,可以省略大括号 - 1 
 2
 3
 4
 5
 6- class Person(var name: String, var username: String) { 
 /**构造函数函数体*/
 init {
 }
 }
- 任何类继承自Any(类似Object)可以继承其他类,所有类默认不可继承(final),所有只能继承那些声明open或者abstract的类,指定父类中的参数 - 1 
 2- open class Animal(name: String) 
 class Person(name: String, surname: String) : Animal(name)
函数
- fun关键字定义函数,没有指定返回值时,返回Unit类似void,但是Unit是一个对象- 1 
 2
 3
 4
 5
 6
 7
 8- fun onCreate(savedInstanceState: Bundle?) { 
 }
 fun add(x: Int, y: Int) : Int {
 return x + y
 }
 fun add(x: Int,y: Int) : Int = x + y
- 构造方法和函数参数 - 指定参数默认值 - 1 
 2
 3
 4
 5
 6
 7- fun toast(message: String, length: Int = Toast.LENGTH_SHORT) { 
 Toast.makeText(this, message, length).show()
 }
 避免重载函数,第二个参数可不传
 toast("Hello")
 toast("Hello", Toast.LENGTH_LONG)
- 三个参数,避免重载函数,string引用模板 - [$className] $message,- ${user.name}
 - 1 
 2
 3
 4
 5
 6
 7- private fun toast(message: CharSequence, tag: String = "MainActivity", duration: Int = Toast.LENGTH_SHORT) { 
 Toast.makeText(this, "[$tag] $message", duration).show()
 }
 toast("Hello")
 toast("Hello", "MyTag")
 toast("Hello", "MyTag", Toast.LENGTH_SHORT)
创建一个layout
- 列表使用recyclerview - 1 
 2
 3
 4
 5
 6- implementation "com.android.support:recyclerview-v7:$support_version" 
 
 val forcastList = findViewById(R.id.recyclerView) as RecyclerView
 //通过属性赋值的方式设置LayoutManager(对象实例化没有使用new关键字),而不是通过setter
 forcastList.layoutManager = LinearLayoutManager(this)
- Recycler Adapter - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13- class ForcastListAdapter(val items: List<String>) : RecyclerView.Adapter<ForcastListAdapter.VH>() { 
 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
 return VH(TextView(parent.context))
 }
 override fun getItemCount(): Int = items.size
 override fun onBindViewHolder(holder: VH, position: Int) {
 holder.textView.text = items[position]
 }
 class VH(val textView: TextView) : RecyclerView.ViewHolder(textView)
- 创建数据,设置Adapter,listOf 创建一个常量的List,它接收一个任何类型的 vararg (可变长的参数),它会自动推断出结果的类型。还有很多其它的函数可以选择,比如 setOf , arrayListOf 或者 hashSetOf - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- //val forecastList = findViewById<RecyclerView>(R.id.recyclerView) 
 recyclerView.layoutManager = LinearLayoutManager(this)
 val items = listOf("Mon 6/23 - Sunny - 31/17",
 "Tue 6/24 - Foggy - 21/8",
 "Wed 6/25 - Cloudy - 22/17",
 "Thurs 6/26 - Rainy - 18/11",
 "Fri 6/27 - Foggy - 21/10",
 "Sat 6/28 - TRAPPED IN WEATHERSTATION - 23/18",
 "Sun 6/29 - Sunny - 20/7")
 recyclerView.adapter = ForcastListAdapter(items)
 
变量和属性
基本类型
- 数字类型不会自动转型,做一个明确的类型转换 - 1 
 2
 3
 4
 5- val i:Int=7; 
 val d:Double=i.toDouble()
 Log.e(tag, d.toString())
 E/MainActivity: 7.0
- 字符char的数字值不能直接使用,需要转换为一个数字 - 1 
 2
 3
 4
 5- val c='c' 
 val i2:Int=c.toInt()
 Log.e(tag,i2.toString())
 
 E/MainActivity: 99
- 仅适用Int Long的按位运算,包括 - 1 
 2
 3
 4
 5
 6
 7- shl(bits) – signed shift left (Java's <<) 
 shr(bits) – signed shift right (Java's >>)
 ushr(bits) – unsigned shift right (Java's >>>)
 and(bits) – bitwise and
 or(bits) – bitwise or
 xor(bits) – bitwise xor
 inv() – bitwise inversion- 示例1 
 2
 3
 4
 5
 6
 7
 8
 9val FLAG1 = 8L 
 val FLAG2 = 16L
 //按位运算,Int Long可用
 val bitwiseOr = FLAG1 or FLAG2
 val bitwiseAnd = FLAG1 and FLAG2
 Log.e(tag, bitwiseOr.toString())
 Log.e(tag, bitwiseAnd.toString())
 E/MainActivity: 24
 E/MainActivity: 0
 
- 示例
- string字符串的访问 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16- //string 可以像数组一样访问 
 val s = "Example"
 val c1 = s[2]
 Log.e(tag, c1.toString())
 for (c in s) {
 Log.e(tag, "item =$c")
 }
 E/MainActivity: a
 E/MainActivity: item =E
 E/MainActivity: item =x
 E/MainActivity: item =a
 E/MainActivity: item =m
 E/MainActivity: item =p
 E/MainActivity: item =l
 E/MainActivity: item =e
变量
- 变量可以很简单地定义成可变( var )和不可变( val )的变量,不可变对象也可以说是线程安全的,因为它们无法去改变,也不需要去定义访问控制,因为所有线程访问到的对象都是同一个,尽量使用val,自动从赋值语句判断变量类型1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11val actionBar = supportActionBar 
 Log.e(tag, actionBar.toString())
 val a: Any = 23
 Log.e(tag, a.toString())
 val c: Context = this
 Log.e(tag, c.toString())
 E/MainActivity: android.support.v7.app.WindowDecorActionBar@2511c44
 E/MainActivity: 23
 E/MainActivity: com.willkernel.app.kotlindemo.MainActivity@b16dc5a
属性
- 当操作Java代码的时候,Kotlin将允许使用属性的语法去访问在Java文件中定义的getter/setter方法。编译器会直接链接到它原始的getter/setter方法。所以当我们直接访问属性的时候不会有性能开销
- 在getter和setter中访问这个属性自身的值,它需要创建一个 backingfield 。可以使用 field 这个预留字段来访问,它会被编译器找到正在使用的并自动创建。需要注意的是,如果我们直接调用了属性,那我们会使用setter和getter而不是直接访问这个属性。 backing field 只能在属性访问器内访问1 
 2
 3
 4
 5var nick: String = "" 
 get() = field.toUpperCase()
 set(value) {
 field = "Name: $nick"
 }
 
     
        