這是該系列的第一篇,系列文章目錄以下:java
這個系列記錄的是kotlin
使用感覺,其中也會穿插基礎知識點,並經過項目實戰代碼綜合運用這些知識點。工具
剛接觸kotlin
就被它的簡潔震撼到了(kotlin
的做者必定是一個極簡主義!)。一塊兒來看下kotlin
是怎麼經過「斷舍離」來實現簡潔的:post
新建對象不須要new
關鍵詞。
任何語句的結尾不須要;
但加上也不會有語法錯誤。
//java
StringBuffer buffer = new StringBuffer();
//kotlin
var buffer = StringBuffer()
複製代碼
var
是kotlin
保留字,用於聲明變量。與之對應的是val
用於聲明常量,常量意思是引用不可變,但並不表明其引用對象也不可變。kotlin
會根據上下文推斷變量類型,這種能力稱爲 「類型推導」 。var buffer: StringBuffer = StringBuffer()
複製代碼
kotlin
中類型是後置的,在變量名後跟上: 類型
就能夠顯示指定類型。同理,它也用於指定函數返回值類型:fun getMessage(): String{
return "message"
}
複製代碼
fun
關鍵字用於聲明函數。//java
public class CheckableActivity extends Activity {
final public void setStatus(){}
}
public class MyListener implements View.OnClickListener{
@Override
public void onClick(View v) {
}
}
//kotlin
class CirclePartyListActivity : Activity() {
fun setStatus(){}
}
class MyListener : View.OnClickListener{
override fun onClick(v: View?) {
}
}
複製代碼
kotlin
用 :
取代了implements
和extends
保留字。
@Override
也被override
保留字取代而且和函數頭同行,kotlin
中的override
是必須的,而java
中是可選的。
kotlin
中類和方法默認是final
的(可省略不寫),這意味着默認狀況下,類和方法是不容許被繼承和重寫的(這是爲了防止脆弱的基類
,即對基類方法的修改會致使子類出現預期以外的行爲)。只有經過open
保留字顯示聲明該類或方法能夠被繼承或重寫:
open class A{
open fun do(){
}
}
複製代碼
kotlin
的lambda
也更加簡約:
//正常狀況
view.setOnClickListener({ v -> v.setVisibility(View.INVISIBLE) })
//當lambda是函數的最後一個參數時,能夠將其移到括號外面
view.setOnClickListener() { v -> v.setVisibility(View.INVISIBLE) }
//當函數只有一個lambda類型的參數,能夠去省去括號
view.setOnClickListener { v -> v.setVisibility(View.INVISIBLE) }
//當lambda只有一個參數,可省去參數列表,在表達式部分用it引用參數
view.setOnClickListener { it.setVisibility(View.INVISIBLE) }
複製代碼
java
中,字段和其訪問器的組合被稱爲屬性,kotlin
引入了property access syntax
,它取代了字段和訪問器方法,用這種方式進一步簡化上面的代碼:
view.setOnClickListener { it.visibility = View.INVISIBLE }
複製代碼
getter
和setter
方法的字段,在kotlin
中均可以經過賦值語法來操做。kotlin
中的語句和表達式的惟一區別是:表達式有值,而語句沒有。若是函數體由單個表達式構成,能夠省去花括號和return,並用賦值的=
表示將表達式的值賦值給返回值,這種語法叫表達式函數體:
//java
public int add(int a, int b){
return a+b ;
}
//kotlin
fun add(a: Int, b: Int): Int = a+b
複製代碼
在 lambda 表達式中包含多條語句或表達式時,若省略return
,則默認將最後一個表達式的值做爲返回值:
view.setOnTouchListener { v, event ->
...//do something
false
}
複製代碼
上述代碼表示在OnTouchListener.onTouch()
中返回 false。
//java
String color;
switch(colorInt){
case Color.RED:
color = "red";
break;
case Color.BLUE:
color = "blue";
break;
default:
color = "black";
break;
}
//kotlin
val color = when (colorInt) {
Color.RED -> "red"
Color.BLUE -> "blue"
else -> "black"
}
複製代碼
when
用於取代switch-case
,不須要在每一個分支末尾調用break
,若是有一個分支命中則會當即返回。when
是一個表達式,這意味着它有返回值,返回值等於命中分支中最後一條語句的返回值。java
中的default
保留字用於接口中默認方法的實現。在kotlin
中能夠省去它。
//java
public interface IMessage {
default String getMessage() {
return "default message";
}
int getMessageId();
}
//kotlin
interface IMessage {
fun getMessage(): String {
return "default message"
}
fun getMessageId(): Int
}
複製代碼
Int
是java
中基本數據類型int
的包裝類,kotlin
中沒有基本數據類型。//java
public class Address {
private String country;
public String getCountry() {
return country;
}
}
public class Company {
private Address address;
public Address getAddress() {
return address;
}
}
public class Person {
private Company company;
public String getCountry() {
String country = null;
//屢次防護式編程
if (company != null) {
if (company.getAddress() != null) {
country = company.getAddress().getCountry();
}
}
return country;
}
}
//kotlin
fun Person.getCountry(): String? {
return this.company?.address?.country
}
複製代碼
?.
稱爲 安全調用運算符 ,它把判空檢查和一次方法調用合併成一個操做。只有當調用變量不爲null
時,纔會執行調用,不然整個表達式返回null
。這意味着,再也不須要防護式編程。?
置於類型以後表示這個類型可空,上面的函數聲明表示此函數的返回值可能爲null
。Person
類添加了一個getCountry()
方法,這種技術叫擴展函數 。擴展函數是一個類的成員函數,但它定義在類體外面。這樣定義的好處是,能夠在任什麼時候候任何地方給類添加功能。
在擴展函數中,能夠像類的其餘成員函數同樣訪問類的屬性和方法(除了被private
和protected
修飾的成員)。還能夠經過this
引用類的實例,也能夠省略它,把上段代碼進一步簡化:
fun Person.getCountry(): String? {
return company?.address?.country
}
複製代碼
kotlin
預約了不少擴展函數,下面就會用到其中的apply
:
編程中常常會遇到「對同一個對象作屢次操做」的場景,好比:
Intent intent = new Intent(this, Activity1.class);
intent.setAction("actionA");
Bundle bundle = new Bundle();
bundle.putString("content","hello");
bundle.putString("sender","taylor");
intent.putExtras(bundle);
startActivity(intent);
複製代碼
其中,對象intent
和bundle
重複出現若干次,這對於極簡主義的kotlin
來講不能忍,它的表達方式以下:
Intent(this,Activity1::class.java).apply {
action = "actionA"
putExtras(Bundle().apply {
putString("content","hello")
putString("sender","taylor")
})
startActivity(this)
}
複製代碼
其中,apply
的定義以下:
//爲泛型T對象添加新功能apply(),它接受一個lambda類型的參數block,且lambda調用的發起者是對象自己
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
//執行lambda
block()
//返回調用者自身
return this
}
複製代碼
對於object.apply{lambda}
能夠簡單的理解爲:在object對象上應用lambda操做,而且最終返回object對象自己。因此上述代碼也能夠寫成更加緊湊的形式:
startActivity(Intent(this, Activity1::class.java).apply {
action = "actionA"
putExtras(Bundle().apply {
putString("content", "hello")
putString("sender", "taylor")
})
})
複製代碼
同一類型的預約義擴展函數還包括with
、let
、also
。它們的共同點是適用於 「對同一個對象作屢次操做」 的場景 。它們的不一樣點總結以下:
函數 | 返回值 | 調用者角色 | 如何引用調用者 |
---|---|---|---|
also | 調用者自己 | 做爲lambda參數 | it |
apply | 調用者自己 | 做爲lambda接收者 | this |
let | lambda返回值 | 做爲lambda參數 | it |
with | lambda返回值 | 做爲lambda接收者 | this |
kotlin
中,發起調用擴展函數的那個對象,叫接收者對象。同理,發起調用lambda的對象叫作lambda接收者。also
的源碼和apply
作對比,更好的理解他們調用者角色的差異://爲泛型T對象添加新功能also(),它接受一個lambda類型的參數block,且對象是lambda的參數
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
複製代碼
「讓 app 中全部被點擊的 View 都帶上縮放動畫」。綜合運用上述kotlin
知識點實現這個需求以前,先來看看java
是如何實現的:
View
分別設置觸摸和單擊監聽器。在按下時播放動畫,鬆手時反向播放動畫。public class ViewUtil {
public static void addExtraAnimClickListener(View view, ValueAnimator animator, View.OnClickListener listener) {
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
animator.start();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
animator.reverse();
break;
}
//若返回true,則屏蔽了點擊事件
return false;
}
});
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (listener != null) {
listener.onClick(v);
}
}
});
}
}
複製代碼
Button btn3 = findViewById(R.id.btn3);
//新建動畫:變大
ValueAnimator animator = ValueAnimator.ofFloat(1.0f, 1.2f);
animator.setDuration(100);
animator.setInterpolator(new AccelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float value = ((Float) animation.getAnimatedValue());
btn3.setScaleX(value);
btn3.setScaleY(value);
}
});
//點擊響應邏輯
View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(Activity1.this, "spring anim", Toast.LENGTH_LONG).show();
}
};
//應用工具類
ViewUtil.addExtraAnimClickListener(btn3, animator, onClickListener);
複製代碼
不要眨眼,換kotlin
閃亮登場:
//擴展函數接收一個動畫和一個點擊響應邏輯(用lambda表示)
fun View.extraAnimClickListener(animator: ValueAnimator, action: (View) -> Unit) {
setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> animator.start()
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> animator.reverse()
}
false
}
setOnClickListener { action(this) }
}
複製代碼
btnSpringAnim.extraAnimClickListener(ValueAnimator.ofFloat(1.0f, 1.15f).apply {
interpolator = AccelerateInterpolator()
duration = 100
addUpdateListener {
btnSpringAnim.scaleX = it.animatedValue as Float
btnSpringAnim.scaleY = it.animatedValue as Float
}
}) { Toast.makeText(this, "spring anim", Toast.LENGTH_LONG).show() }
複製代碼
btnSpringAnim
是一個Button
控件的id(只要裝了kotlin插件,就不須要findViewById())as
保留字用於類型強制轉換。kotlin
憑藉着極強的表達力用將近 1/3 的代碼量完成了功能。var
保留詞用於聲明變量,val
保留詞用於聲明常量。大多數狀況下不須要顯示指明變量類型,kotlin 具備類型推導能力,會根據上下文自動推斷類型。fun
保留字用於聲明函數。override
保留字表示重寫父類方法或者實現接口中的抽象方法,與 java 不一樣的是,它必須顯示出如今重寫方法前( java 容許省略)。as
保留字用於類型強制轉換。: 類型
就能夠顯示指定類型。:
還用於繼承類(取代extends
)、實現接口(取代implements
)。new
,而是直接調用構造函數。;
但加上也不會有語法錯誤。final
的,他們不能被繼承和重寫。只有經過加上open
後才能被繼承和重寫。default
關鍵字。when
保留字用於取代switch-case
,並且它是一個表達式,返回值是命中分支中最後一表達式的值。property access syntax
,再也不須要getter和setter方法,能夠直接對屬性賦值。?.
稱爲 安全調用運算符 ,只有當調用變量不爲null
時,纔會執行調用,不然整個表達式返回null
。這樣就避免了防護式編程。?
置於類型以後表示這個類型的變量或返回值值可能爲null
。also()
、apply()
、let()
、with()
。最近開始學習 kotlin ,研讀《Kotlin實戰》的同時,在項目中加以運用。這個系列會不斷地新增來自書本和實踐中的新發現。但願對你能有所幫助~~