一、類與方法
1,類
類的聲明
class Bar(var b: Int): Foo() { var c = 1 init { println("class initializer") } constructor(): this(1) { println("secondary constructor") } }
Bar類在這裏繼承了Foo類,Bar類有兩個構造函數,直接在Bar類頭的是primary constructor,另外一個構造函數使用constructor關鍵字定義,注意必須要先調用primary constructor,另外,init標明的是class initializer,每個構造函數都會首先調用class initializer裏面的代碼,再調用構造函數
創建類的實例,不需要 new
var bar = Bar()
繼承
內定義默認是 final 的,要想能被繼承,基類頭必須有 open 註解
Inner class
class Outer { class Inner { } }
與 Java 不同,Kotlin 中所有的內部類默認就是靜態的,這樣可以減少很多內存泄露的問題。如果需要在內部類中引用外部類對象,可以在Inner類的聲明前加上inner關鍵字,然後在Inner類中使用標記的this:this@Outer來指向外部類對象
Singleton
object Single { var c = 1 fun foo() = println("foo") }
單利對象用 object 關鍵字表示,可以直接使用 Single.foo() 來調用了
2,接口
interface Interface {
fun foo() {
println(1)
}
fun bar()
}
可以帶有默認的實現方法,並且不允許通過屬性來維護狀態。
3,函數
函數聲明
fun foo(va: Int): Int { return 1 }
也可以使用單行聲明
fun foo(va: Int): Int = 1
重載
與類的派生一樣,允許重載的方法要有open註解,而在派生類中重載時要使用override註解
override fun foo(va: Int): Int { return 2 }
4,修飾符
5,成員變量的 Get 與 Set
注:
1,類和方法默認定義都是 final,以此來提高效率。類想要被繼承用 open 關鍵字
2,類 和 成員變量 默認是 public 修飾
二、語法
1,語法糖,對類的擴充
在不修改類的原始定義的情況下實現對類的擴展,如下面的代碼爲Person類增加了一個名爲isTeenager的擴展:
fun Person.isTeenager(): Boolean {
return age in 13..19
}
2,排除空指針
定義一個爲空的變量是需要加上 ? 符號
var text: String? = null
操作一個可能爲空的對象時,同樣要加上 ? 符號
var length = text?.length
如果將該變量傳遞給函數,在參數後面需要加 !! 符號
if (text != null) { customPrint(text!!) }
如何去掉 !! 符號呢,當代碼充滿該符號時顯然很不優雅,這時可以使用 let 函數
text?.let { customPrint(it) }
如果遇到多個參數的情況,你可以選擇嵌套多個 let,但這樣可讀性並不好。比如:
if (mUserName != null && mPhotoUrl != null) { uploadPhoto(mUserName!!, mPhotoUrl!!) }
這時你可以構建一個全局函數:
fun <T1, T2> ifNotNull(value1: T1?, value2: T2?, bothNotNull: (T1, T2) -> (Unit)) { if (value1 != null && value2 != null) { bothNotNull(value1, value2) } }
調用方式
ifNotNull(mUserName, mPhotoUrl, {name, url -> uploadPhoto(name, url) })
3,高階函數和Lambda表達式
例如給一個變量賦 lambda 表達式 {x,y->x+y}
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
定義一個可以傳表達式的高階函數
fun doubleTheResult(x:Int, y:Int, f:(Int, Int)->Int): Int { return f(x,y) * 2 }
調用方法如下
val result1 = doubleTheResult(3, 4, sumLambda) 或 val result2 = doubleTheResult(3, 4, {x,y -> x+y})
4,範圍表達式
範圍創建只需要 .. 操作符,爲升序,例如:
// 該範圍包含數值1,2,3,4,5 val r1 = 1..5
如果要表示降序,用 downTo 函數
// 該範圍包含數值5,4,3,2,1 val r2 = 5 downTo 1
如果步長不是1,則需要使用step函數
// 該範圍包含數值5,3,1 val r3 = 5 downTo 1 step 2 // 同理,升序的序列 val r4 = 1..10 step 2
5,條件結構
if 表達式(類似於 Java 的 ?: 運算符)
var age = 20 val isEligibleToVote = if(age > 18) "Yes" else "No"
when表達式(類似於 Java 的 switch,但功能更強大)
val age = 17 val typeOfPerson = when(age){ 0 -> "New born" in 1..12 -> "Child" in 13..19 -> "Teenager" else -> "Adult" }
6,循環結構
使用 for..in 遍歷數組、集合及其它提供了迭代器的數據結構,語法同Java幾乎完全相同,只是用 in 操作符取代了 : 操作符
val names = arrayOf("Jake", "Jill", "Ashley", "Bill")
for (name in names) {
println(name)
}
while 和 do..while 循環的語法與Java完全相同。
7,字符串模板
可以在字符串中嵌入變量和表達式,例如:
val name = "Bob"
println("My name is ${name}") //打印"My name is Bob"
val a = 10
val b = 20
println("The sum is ${a+b}") //打印"The sum is 30"
三、XML 佈局 + kotlin-android-extensions
1, 通常在 xml 中查找控件的寫法
val name = find<TextView>(R.id.tv_name)
// 等同於 findViewById()
val name = findViewById(R.id.tv_name) as TextView
name.text="張三"
2,如果使用擴展後,可以直接調用並賦值
tv_name.text="張三"
環境配置
1,項目下面的 build.gradle 加入如下代碼:
buildscript {
ext.kotlin_version ="1.0.4"
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
2,app 下面的 build.gradle 加入如下代碼:
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
sourceSets{
main.java.srcDirs+='src/main/kotlin'
}
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile 'org.jetbrains.anko:anko-sdk25:0.10.0-beta-1'// sdk15, sdk19, sdk21, sdk23 are also available
compile 'org.jetbrains.anko:anko-appcompat-v7:0.10.0-beta-1'
}
3,Gradle Sync
4,菜單欄 —> Code —> Convert Java File to Kotlin File
Anko Layout
一、優點
1,運行速度快。XML佈局是在運行時解析的,也就是說XML需要從資源文件中獲取,然後 XmlPullParser 需要解析所有的元素並一個一個的創建它們。還要解析元素的屬性,然後設置,這個過程非常繁重。
2,類型安全,不再需要那麼多的 findById() 之後的類型轉換。
3,null 安全,Kotlin 裏,如果一個變量用?表示爲可空,並且使用?之後再調用的時候,即使變量爲空也不會引發異常。
4,代碼複用,可以通過繼承AnkoComponent的方式實現代碼複用。XML佈局是每一個Activity,每一個View各自專屬一個,代碼複用比較少。
二、缺點
1,Anko DSL 佈局不能預覽。雖然有一個叫 Anko Preview Plugin 的預覽插件,但是每次修改後都需要 make 下才能預覽,關鍵是在新版本 Android Studio2.2 以上都不支持。
- 筆者在 Android studio2.3 上安裝該插件,導致重啓後無法進入項目界面。
- 幸好在啓動頁面的左下角有一個
Config
選項,點擊其中的Plugin
,卸載Anko Preview
插件纔可以正常啓動。
2,定義 id 比較繁瑣,需要定義一個變量,或者在 values 資源文件下定義 ids。不用 id 行不行呢?你去問問 RelativeLayout 答應不答應吧。
3,如果定義在 xml 的話,可以直接通過 id 使用對應的 View(XML 佈局 + kotlin-android-extensions 的方式),但是在 Anko DSL 佈局的話,只能通過定義變量的方式來實現。
4,動態替換外部資源以達到換膚的效果,那麼 XML 顯然比 Kotlin 代碼要來得容易:前者可以編譯成一個只有資源的 apk 供應用加載,後者的話就得搞一下動態類加載了。
三、引用方式
// 繼承 AnkoComponent 創建佈局
class LoginLayout<T> : AnkoComponent<T> {
override fun createView(ui: AnkoContext<T>): View {
return with(ui){
...
}
}
}
// Activity 中引用
override fun onCreate(savedInstanceState: Bundle?) {
LoginLayout<MainActivity>().setContentView(this)
}
// Fragment 中引用
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
var view = LoginLayout<LoginFragment>().createView(AnkoContext.create(context, LoginFragment()))
return view
}
四、常用語法
1,定義 TextView
textView("Hello") {
textSize = 16f
textColor = Color.RED
backgroundResource = R.drawable.shape_et_bg
gravity = Gravity.CENTER
}.lparams(matchParent, wrapContent){
margin = dip(12)
padding = dip(2)
}
2,提取樣式
// 給 EditText 擴展樣式方法
fun EditText.commonStyle(){
textSize = 16f
backgroundResource = R.drawable.shape_et_bg
}
// 直接在佈局的後面添加上
.style {
view ->
when (view) {
is Button -> {
view.gravity = Gravity.CENTER
}
is TextView -> {
view.gravity = Gravity.LEFT
view.textSize = 20f
view.textColor = Color.DKGRAY
}
}
}
3,設置點擊事件
var etInput = editText {
hint = "請輸入文字"
commonStyle()
}
button("點我"){
// 在按鈕屬性內部設置點擊事件
onClick {
toast("輸入的內容:${etInput.text}")
}
}
// 通過變量 + . 的方式設置
etInput.onClick {
}
4,佈局方式
val ID_USERNAME = 1
// 垂直佈局,== LinearLayout + orientation="vertical"
verticalLayout { }
// 相對佈局,需要使用到 ID
relativeLayout {
textView("姓名") {
id = ID_USERNAME
}
textView("描述") {
}.lparams {
below(ID_USERNAME)
alignParentLeft()
}
}
// 線性佈局
linearLayout {
orientation = LinearLayout.HORIZONTAL
}
frameLayout { }
tableLayout { }
5,ui: AnkoContext
// 包含的變量
val ctx: Context
val owner: T
val view: View
// 例如,可以通過 owner 直接調用外部 Activity 的方法
override fun createView(ui: AnkoContext<T>): View {
if (ui.owner is Activity) {
(owner as Activity).onBackPressed()
}
}
參考鏈接
Kotlin Primer·第二章·基本語法 https://kymjs.com/code/2017/02/04/01/
http://blog.csdn.net/io_field/article/details/53365834
只需五分鐘,開始使用Kotlin開發Android
https://barryhappy.github.io/2016/10/20/start-kotlin-in-5-mins/
登陸註冊 Demo
http://blog.csdn.net/xiehuimx/article/details/72354371
Kotlin 系統入門到進階 視頻教程 https://github.com/enbandari/Kotlin-Tutorials