kotlin學習記錄

kotlin

將一個activity的java文件轉(zhuǎn)為kotlin文件

最簡單的轉(zhuǎn)化方式

android stutdio支持一鍵轉(zhuǎn)化的方式继阻,通過快捷鍵ctrl +alt + shift + k將整個java文件轉(zhuǎn)化為kt文件宏蛉,不過可能需要自己解決一些代碼不一致的沖突囱修,而且有些時候轉(zhuǎn)化后的代碼和我們直接寫的代碼還是有差別的口柳。

環(huán)境配置

kotlin庫引入

android studio3.0默認支持kotlin芥挣,雖然是默認支持kotlin,但也是需要增加一些配置扶檐,不過這個as已經(jīng)給我們做好了智能提示和自動添加的功能葫松。在我們第一次創(chuàng)建出kt文件的時候瓦糕,將會有一個kotlin的配置提示,我們只需要點擊configure腋么,然后選擇全局配置咕娄,那么as將會在gradle中添加上kotlin的依賴
[圖片上傳失敗...(image-4852fe-1542511738777)]
gradle文件如下所示:
[圖片上傳失敗...(image-17de9f-1542511738777)]
這樣我們就使用kotlin的代碼庫了。

kotlin extension庫引入

之前項目中用的是view的綁定庫是ButterKnife珊擂,就個人而言圣勒,還是覺得挺好用的,畢竟綁定View的代碼都能自動生成摧扇,不過如果在kt文件中圣贸,不能直接引入這個庫,需要重新引入kotlin中的ButterKnife庫https://github.com/JakeWharton/kotterknife扛稽,不過我們可以不用這個庫了吁峻,因為kotlin給我們提供了一套更為簡便的庫,我們只需要在gradle中引入kotlin-extension在张,并且在kt文件中import相對應的xml用含,就能直接通過id的方式引用view。

//在kt文件中
import kotlinx.android.synthetic.main.activity_member_center.*

//在gradle文件中
apply plugin: 'kotlin-android-extensions'

比如說我們在xml中有這樣一個View:

 <android.support.v7.widget.RecyclerView
        android:id="@+id/memberRv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/member_center_tool_bar"
        android:layout_centerHorizontal="true" />

這樣我們在kt文件中帮匾,可以像下面的方式這樣調(diào)用:

private fun initRv() {
        adapter = MemberInfoAdapter(this, null)
        memberRv.layoutManager = LinearLayoutManager(this)
        memberRv.itemAnimator?.changeDuration = 0
        memberRv.adapter = adapter
    }

這個memberRv就是RecyclerView在xml中指定的id啄骇。

一些常用用法

參數(shù)定義

修飾符

在kotlin中,聲明所有變量都需要3個關鍵字修飾瘟斜,var缸夹、val和const。在kotlin中是沒有final修飾符的哼转,final修飾符在kotlin中其實就相當于val

  • var:主要是用來修飾可變變量的明未。
  • val:主要是用來修飾不可變變量的,其實也不能說是不可變壹蔓,更好的稱呼是叫做只讀變量,val在修飾變量的時候可以不初始化猫态,但是它不能被賦值佣蓉,在java中披摄,用final修飾的變量必須要初始化,否則編譯不能通過勇凭。舉個val修飾不初始化的例子:
        class a {
        var c = 1;
        val b: String
        fun getB(): String {
            return c > 3 ? "haha" : "xixi"
        }
        
        fun add() {
            c++
        }
        
        }
    
  • const:其實const就和java中的static final一致了疚膊,不能放在局部方法中,在編譯期間必須確定變量值虾标。
靜態(tài)變量及靜態(tài)方法

在java中寓盗,靜態(tài)屬性和靜態(tài)方法只需要一個static屬性就能搞定了,但是在kotlin璧函,它有一個單獨的塊來標識靜態(tài)塊的初始化傀蚌,companion object:

companion object {
        val intentFrom: String = "intent_extra"
        fun startMemberCenterActivity(context: Context,                 launchMemberCenter: LaunchMemberCenter) {
            var intent = Intent(context, TestAc::class.java)
            intent.putExtra(intentFrom, launchMemberCenter)
            if (context is Activity) {
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            context.startActivity(intent)
        }
    }

這個代碼塊有幾個需要注意的點,

  • 在kt定義Intent中蘸吓,class的指定需要已類名::class.java的方式指定善炫,否則在log中會提示找不到activity
  • 在這個靜態(tài)塊中,定義的變量和方法都是靜態(tài)的
  • 在外部如果需要訪問這個塊的方法库继,如果是kotlin文件訪問箩艺,可以直接通過類名.的方式調(diào)用,如果是java文件訪問宪萄,需要通過類名.companion.的方式調(diào)用:
//在java文件中調(diào)用
public void start() {
       TestAc.Companion.startMemberCenterActivity(context, this);
   }
//在kt文件中調(diào)用
public void start() {
       TestAc.startMemberCenterActivity(context, this);
   }
kotlin的空指針安全

在變量定義時艺谆,我們可以通過kotlin特有的方式來標識變量是否可空:

private var adapter: MemberInfoAdapter? = null

只需要的變量類型后面添加?,就表示這個變量是可以為null的拜英,如果不添加擂涛,默認這個變量不能為null。一旦我們添加了?聊记,在后續(xù)的代碼中撒妈,如果有引用到這個變量的地方,如果沒有做判空處理將會編譯不過排监,這個判空處理還是挺方便的狰右,

 override fun refreshDiscoveryList(mixFindInfoList: MutableList<MixFindInfo>?) {
        adapter?.notifyMixFindInfoChange(mixFindInfoList)
    }

Equality check should be used instead of elvis for nullable boolean check
在調(diào)用時,如果adaper為空了舆床,將不會執(zhí)行后續(xù)的操作棋蚌。
今天遇到了一個符號:

var xie = a ?: ""

這個?:是kotlin的elvis用法,屬于兩目運算符挨队,就是簡單的if谷暮、else縮寫,
當a不為null盛垦,取a的值湿弦,當a為null,取""

接口使用

kotlin接口和java接口的使用區(qū)別

class TestAc : BaseMvpActivity<MemberCenterPresent>(), MemberCenterPresent.MemberInfoChange,
        KKAccountManager.KKAccountChangeListener, View.OnClickListener {

其中BaseMvpActivity繼承腾夯,而其他三個都是接口繼承颊埃。

  • java接口需要用implements關鍵字實現(xiàn)蔬充,而kotlin實現(xiàn)的方式和繼承一樣
  • java接口能夠直接通過匿名內(nèi)部類創(chuàng)建出來,而kotlin也需要先將接口對象創(chuàng)建出來

when表達式

在kotlin中班利,用when表達式將將java中的switch替換掉了饥漫。
最簡單的形式如下:

 override fun onClick(v: View?) {
       when (v?.id) {
           R.id.icBack -> finish()
           R.id.btnOpenLayout -> btnOpenLayoutClick()
           else -> {
           
       }
   }

而且,when里面的條件判斷可以加入比較復雜的判斷罗标,如下:

when (x) {
   in 1..10 -> print("x is in the range")
   in validNumbers -> print("x is valid")
   !in 10..20 -> print("x is outside the range")
   else -> print("none of the above")
}

繼承

kotlin中當含有非空的構造函數(shù)得繼承庸队,有以下這幾種方式:

class MemberCenterAdapter(context: Context?, mixFindInfoList: ArrayList<MixFindInfo>?) : TopicTabListAdapter(context, mixFindInfoList) 

相當于子類的構造器聲明就放在了class的定義上,然后會對應父類相應的構造器闯割。還有另外一種實現(xiàn)方式彻消,主要用于多個構造器的聲明。

constructor(context: Context?, mixFindInfoList: ArrayList<MixFindInfo>?): super(context, mixFindInfoList)

列表

列表元素訪問

在kotlin中纽谒,推薦我們使用下標的方式來訪問元素证膨,就像在訪問數(shù)組一樣。

private var itemTypeList: ArrayList<Int> = ArrayList()
itemTypeList[2] = ITEM_TYPE_ACTIVITY

列表元素遍歷

對于kotlin中的列表遍歷鼓黔,增加了許多遍歷方式央勒。最簡單的如下所示:

//kotlin 
for (i in startIndex..mixFindInfoList!!.size )
//java
for(int i = startIndex; i < mixFindInfoList.size(); i++)

在kotlin中,推薦我們使用until的方式進行遍歷澳化,這樣崔步,我們處理起來也就像是在處理流一樣。

// a until b表示從a到b進行遍歷缎谷,并且將遍歷的值傳遞給下游井濒,
// map將上游傳遞過來的值進行轉(zhuǎn)化,并傳遞給下游
// forEach對轉(zhuǎn)化后的值進行處理
(startIndex until mixFindInfoList!!.size)
                .map { mixFindInfoList[it] }
                .forEach {
                    itemTypeList.add(it.item_type)
                }

三目運算符

之前在java中用慣了三目運算符列林,看著kotlin的三目運算符挺不習慣的瑞你。

//java, 如果a為true,則取b希痴,否則取c 
a ? b : c
//kotlin, 利用if else組成三目運算符者甲,但是不需要括號
if(a) b else c

函數(shù)中流程語句的返回值

在kotlin中,如果多個分支語句都返回值砌创,那么我們可以將返回值放在分支語句的外側(cè)虏缸。

//最原始的版本
when (position) {
    0, 2 -> return null
    1 -> return Utility.getSafely(mixFindInfoList, 0)
    else -> {
        return Utility.getSafely<MixFindInfo>(mixFindInfoList, position - 2)
            }
                }

優(yōu)化后的版本:

return when (position) {
    0, 2 -> null
    1 -> Utility.getSafely(mixFindInfoList, 0)
    else -> {
    Utility.getSafely<MixFindInfo>(mixFindInfoList, position - 2)                }
                }

這種時候,就能夠返回每一個when分支對應的值
對于if else語句也能這么使用

 return if (activityListExist()) {
            if (vipBannerExist()) {
                when (position) {
                    0, 2 -> null
                    1 -> Utility.getSafely(mixFindInfoList, 0)
                    else -> {
                        Utility.getSafely<MixFindInfo>(mixFindInfoList, position - 2)
                    }
                }
            } else {
                if (position == 0 || position == 1) {
                    null
                } else {
                    Utility.getSafely<MixFindInfo>(mixFindInfoList, position - 2)
                }
            }
        } else {
            if (position == 0) {
                null
            } else {
                Utility.getSafely<MixFindInfo>(mixFindInfoList, position - 1)
            }
        }
    }

這種時候嫩实,每一種判斷的分支對應一個值刽辙,返回命中的分支對應的值

類型判斷和類型轉(zhuǎn)換

java中類型判斷和轉(zhuǎn)化:

if (holder instance of MemberVipHeaderHolder) {
    ((MemberVipHeaderHolder)holder).bindData(title, TYPE_VIP_HEADER, isVip, isBtnShow);
}

java中利用instance of進行類型判斷,然后直接通過(type)instance進行類型強轉(zhuǎn)甲献,將instance轉(zhuǎn)化為type類型的實例宰缤。如果instance不是type類型,那么將會拋出類型轉(zhuǎn)化異常。
而在kotlin中撵溃,可以通過as和is關鍵字進行類型判斷和轉(zhuǎn)化

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (getItemViewType(position)) {
            ITEM_TYPE_ACTIVITY -> {
                if (holder is MemberAssignViewHolder) {
                    holder.bindData(activityList)
                }
            }
            ITEM_TYPE_MEMBER_INFO_CARD -> {
                if (holder is MemberInfoCardViewHolder) {
                    holder.bindData()
                }
            }
            else -> {
                holder.itemView.setPadding(0, 0, 0, if (position == itemCount - 1) UIUtil.dp2px(40f) else 0)
                if (holder is BaseViewHolder) {
                    holder.holderType = BaseViewHolder.TYPE_MEMBER
                }
                super.onBindViewHolder(holder, position)
            }
        }
    }

利用 a is type 來判斷a是否是type類型疚鲤,如果是type類型的話锥累,那么kotlin將會自動為我們將a轉(zhuǎn)化為type類型缘挑,而不需要我們再手動的利用as進行類型轉(zhuǎn)化。如果kotlin直接利用as進行類型轉(zhuǎn)化的話桶略,如果類型不一致或者a為null時语淘,也會拋出異常,但是kotlin提供了類型不一致時的安全轉(zhuǎn)化际歼,如下

val x: String ?= y as? String

上面的例子中惶翻,as?是一個安全轉(zhuǎn)化符,如果失敗鹅心,將會返回null吕粗,而不會直接進行類型轉(zhuǎn)化。

lambda

在java中旭愧,需要升級到java8才支持lambda表達颅筋,而kotlin天生支持lambda表達式,lambda表達式的完成語法如下:

val sum = { x: Int, y: Int -> x + y }

上面的例子定義了一個函數(shù)输枯,求得sum = x + y,lambda表達式總是括在大括號中议泵,完整的參數(shù)聲明和表達式都放在大括號內(nèi),函數(shù)體在->之后桃熄,->之前都是參數(shù)先口,并且可能有類型標注,如果推斷出該lambda的返回值類型不是Unit瞳收,也就是返回值不為空碉京,那么該lambda主體的最后一個表達式將被視為返回值
下面是某一個lambda的例子:

FindExchangeManager.getInstance().loadExchangeData(mContext, findInfo.discoveryModuleId,
                    holder.adapterPosition, findInfo, FindExchangeManager.ExchangeCallback { data, position, discoveryModuleId ->
                if (Utility.isEmpty(mContext)) {
                    return@ExchangeCallback
                }

                val info = getMixInfoFromPosition(position)
                if (data != null && info != null) {
                    info.topics = data
                    notifyItemChanged(position)
                }
            })

如果在lambda表達式中調(diào)用return,將會直接return掉整個上層函數(shù)螟深,因為lambda表達式只是一個代碼塊谐宙,雖然看起來功能像是函數(shù),不過也不能說在lambda表達式中不能夠return血崭,只要給return指定一個標簽卧惜,就會結束掉標簽所指定的代碼塊,就像上面的例子夹纫,這個lambda表達式是在ExchangeCallback中使用的咽瓷,如果要結束這個lambda,那么只需要在lambda中return代碼添加上@ExchangeCallback標簽就行舰讹,就繪結束掉ExchangeCallback的這個方法茅姜。

ViewHolder中使用kotlin extension

kotlin extension的使用需要先導入相應的xml

//在上一篇的activity中
import kotlinx.android.synthetic.main.activity_member_center.*

//在這個viewHolder中
import kotlinx.android.synthetic.main.listitem_assign.view.*

對于這個導包操作,需要注意的是,kotlinx.android.synthetic.main是固定前綴钻洒,后面的是當前頁面的layout文件名稱奋姿,如果是activity,只需要再在后面添加上.素标,那就能夠在activity中直接以id的形式調(diào)用對應的View称诗。如果是在viewHolder中,那么還需要添加上.view,在添加.才能夠使用头遭,而且在viewHolder中寓免,需要以其itemView為持有者來調(diào)用。

init {
        context = itemView.context
        itemView.btn_get_gift.setOnClickListener(this)
        itemView.btn_not_gift.setOnClickListener(this)
    }

如上所示计维,利用itemView來持有其中的view的id袜香,并直接調(diào)用。
這個init塊鲫惶,通常都是來做類的初始化的蜈首,在構造器執(zhí)行完之后,會調(diào)用這個init塊欠母,我們?nèi)绻惺裁葱枰龀跏蓟幕恫撸恍枰旁谶@個init塊中

String 轉(zhuǎn)其他類型

java中String轉(zhuǎn)long類型的話,需要調(diào)用Long.paras(string)進行轉(zhuǎn)化艺蝴,如果string不是相應的的類型猬腰,那么將會拋出異常。而在kotlin中也有這個方法猜敢,不過還新增了幾個轉(zhuǎn)化的方法:

//如果string不是一個合法的類型姑荷,那么將會拋出異常NumberFormatException
string.toLong()

//如果string不是一個合法的類型,那么將會返回null
string.toLongOrNull()

結合rxjava

kotlin中有專門的rx-kotlin庫缩擂,剛開始并沒有引入這個庫鼠冕,所以嘗試著還是使用rxjava

Observable.timer(getDelayTime(), TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    getGrabResult(activityId, thirdId)
                })

還是一樣的用法,不過好的一點是可以使用lambda表達式了胯盯,subscribe({})中間的花括號就是lambda表達式

todo標注

在java中懈费,使用todo標識并不會出現(xiàn)什么問題,在kotlin中博脑,一旦我們實現(xiàn)了接口或者抽象類憎乙,那么我們自動生成的實現(xiàn)方法,將會帶上kotlin的todo標注

override fun refreshServerTime(time: Long?) {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

如果我們沒有刪除掉todo這行代碼叉趣,那么kotlin將會直接報錯泞边,kotlin.NotImplementedError,因為這個todo是kotlin默認我們將會刪除掉的疗杉,如果在運行時還存在阵谚,那么執(zhí)行到todo,并不會跳過,而是會執(zhí)行梢什,然后報錯奠蹬。

kotlin標注

在kotlin中,如果需要在kotlin的高階函數(shù)表達式返回嗡午,而不需要直接在外層函數(shù)中返回囤躁,或者嵌套循環(huán),想從內(nèi)層循環(huán)終止外層循環(huán)等翼馆,這種時候我們就需要用到kotlin的label了割以。比如說下面的例子:

private fun canAutoContinue(pos: Int): Boolean {
        if (commonGoodList == null || continueGoodList == null || commonGoodList!!.size < pos) {
            return false
        }
        val commonGood: RechargeGood? = commonGoodList!![pos]

        continueGoodList!!.forEach {
            if (it.upRenewId == commonGood?.id) {
                return true
            }
        }
        print("1111")
        return false
    }

上面的在forEach中金度,return的執(zhí)行將會直接將會結束掉canAutoContinue方法应媚,如果我們只想結束掉forEach,我們可以像下面這樣做猜极。

private fun canAutoContinue(pos: Int): Boolean {
        if (commonGoodList == null || continueGoodList == null || commonGoodList!!.size < pos) {
            return false
        }
        val commonGood: RechargeGood? = commonGoodList!![pos]

        continueGoodList!!.forEach lit@{
            if (it.upRenewId == commonGood?.id) {
                return@lit
            }
        }
        print("1111")
        return false
    }

如上面的lit label中姜,那么這樣return將會結束lit所指定的lable循環(huán),從而繼續(xù)往下執(zhí)行跟伏。
比如說for循環(huán)嵌套

outFor@ for(x in 1..5) {
            for (y in 1..6) {
                if(x == y) {
                    break@outFor
                }
            }
        }

一旦滿足了x==y丢胚,然么將會直接跳出外層的for循環(huán),否則一般的break受扳,只會中斷內(nèi)層的for循環(huán)携龟。要為一個表達式加標簽,我們只要在其前加標簽即可勘高。
在返回和跳轉(zhuǎn)語句中峡蟋,可以指定標簽來表示結束哪個標簽對應的代碼段
如果需要在lambda表達式

kotlin 定義屬性時的get和set方法

kotlin定義屬性時,可以同時定義get和set方法华望,而不需要再重新定義方法去賦值蕊蝗。

private var delayTime: Long
        private set(value) {
            delayTime = value
        }
        get() {
            return KKConfigManager.getInstance().
                    getConfig(KKConfigManager.ConfigType.GET_RECHARGE_ORDER_DELAY)
                    .toLongOrNull() ?: 1000
        }

而且,可以添加上訪問限定符赖舟。而這個get和set方法的設置蓬戚,主要是通過代碼中的位置來標示修飾的哪個變量。

kotlin的幕后字段

Kotlin 中的類不能有字段宾抓, 然而我們在有時在自定義訪問器時子漩,也就是get和set方法時,需要又一個幕后字段石洗,這個字段是kotlin提供的幢泼,field,我們可以直接使用。

var counter = 0 // 注意:這個初始器直接為幕后字段賦值 set(value) {
if (value >= 0) field = value }


val nameHash:Int = 3
        get() {
            field = 5
            return 10
    }

有可能我們需要臨時緩存變量的值劲腿,因為可能其變量的值可能和返回的值不一致旭绒,所以一旦我們需要知道變量的值,我們便可以通過幕后字段來訪問。

kotlin的幕后屬性

幕后屬性主要用于外部只能讀挥吵,內(nèi)部可以讀寫的需求下出現(xiàn)的重父。例如下面的例子:

val counter get() = _counter
private var _counter = 0

這個_counter就是counter的幕后屬性,外部只能訪問counter忽匈,不能訪問_counter房午,而counter的值又是_counter來指定的。

kotlin的擴展

在kotlin中丹允,if else的三目運算符如下所示:

if(a) x else y

而我們也能通過擴展函數(shù)來擴展boolean

inline fun <T> Boolean.yes(action: () -> T): Boolean {
    if (this) action()
    return this
}

inline fun <T> Boolean.no(action: () -> T): Boolean {
    if (!this) action()
    return this

這樣郭厌,我們在kt文件中,只要引入相應的類雕蔽,定義在文件內(nèi)折柠,而非class下

import com.kuaikan.community.extend.yes

擴展函數(shù)是靜態(tài)解析的,所以不能夠進行重載批狐,這就意味著我們扇售,我們不能重載類原有的方法,比如說collection的add方法等..
對于擴展函數(shù)還有一個非常好用的東西嚣艇,被擴展的類型可以為空承冰,被稱為可空接收者

fun Any?.toString(): String {
if (this == null) return "null"
// 空檢測之后,“this”會自動轉(zhuǎn)換為非空類型食零,所以下面的 toString() // 解析為 Any 類的成員函數(shù)
return toString()
}

kotlin的擴展屬性

既然kotlin支持擴展函數(shù)困乒,當然也支持擴展屬性了。

 val <T> List<T>.lastIndex: Int
    get() = size - 1

這樣就給了List的一個屬性lastIndex

kotlin的范型

關于out和in這兩個關鍵字贰谣,out是用來輸出的娜搂,也就是生產(chǎn)者,所以只能作為返回類型冈爹,相當于java中的extends涌攻,用來界定類型上限;in是用來輸入的频伤,所以只能作為消費類型恳谎,in類似于java中的super,用來界定類型下限

kotlin的單例

在kotlin中憋肖,聲明單例變得非常簡單因痛,只需要一個關鍵字object用來修飾對象,就像變量聲明一樣岸更,對象聲明不是一個表達式鸵膏,不能用在賦值語句右邊,對象的初始化是線程安全的怎炊。如果需要引用該對象谭企,我們只需要通過其名稱來調(diào)用廓译。

object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ......
}
val allDataProviders: Collection<DataProvider> get() = // ......
}

//調(diào)用
DataProviderManager.registerDataProvider(......)

伴生對象

類內(nèi)部的伴生對象的聲明如下:

class MyClass { 
    companion object { }
}
val x = MyClass.Companion

請注意,即使伴生對象的成員看起來像其他語言的靜態(tài)成員债查,在運行時他們?nèi)匀皇钦鎸崒ο蟮膶嵗蓡T非区,而且,例如還可以實現(xiàn)接口:

interface Factory<T> { fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass() }
}

如果我們想將伴生對象的成員生成為真正的靜態(tài)方法和字段盹廷,我們我們可以使用@JvmStatic注解

對象表達式和對象聲明之間的語義差異

對象表達式和對象聲明之間有一個重要的語義差別:

  • 對象表達式是在使用他們的地方立即執(zhí)行(及初始化)的;
  • 對象聲明是在第一次被訪問到時延遲初始化的;
  • 伴生對象的初始化是在相應的類被加載(解析)時征绸,與 Java 靜態(tài)初始化器的語義相匹配。

onAttachedToWindow和onDetachedFromWindow

這個是無關kotlin的俄占,只是剛好在寫kt代碼時遇到的一個問題管怠,
關于onAttachedToWindow和onDetachedFromWindow的觸發(fā)時機,

onAttachedToWindow就是在這個View被添加到Window時觸發(fā)的

顧名思義缸榄,onAttachedToWindow就是在這個View被添加到Window時觸發(fā)的渤弛,通過了dispatchAttachedToWindow這個方法觸發(fā)的,那么View被添加到window的時機又是什么碰凶,其實就是對應的activity在生命周期onResume的時候調(diào)用的暮芭,activity對應的view在onResume的時候被添加添加到window。且每一個view都只會被調(diào)用一次欲低,父view調(diào)用在前,不論view的visibility狀態(tài)都會被調(diào)用畜晰,適合做些view特定的初始化操作砾莱;

onDetachedFromWindow

onDetachedFromWindow方法是在activity的生命周期destroy的時候被調(diào)用的,也就是act對應的view從window中移除的時候凄鼻,且每個view只會被調(diào)用一次腊瑟,父view的調(diào)用在后,也不論view的visibility狀態(tài)都會被調(diào)用块蚌,適合做最后的清理操作闰非;

kotlin類的繼承性

java的class默認都是可以繼承的,只有在聲明為final的class才是不可繼承的峭范。而kotlin卻是相反的财松,默認的類都是不可繼承的,也就是默認的修飾符為final纱控,只有顯式的聲明為open的類才是可以繼承的辆毡。而對于抽象類,java和kotlin默認都是可以繼承的甜害,但是子類必須是抽象類或者實現(xiàn)了該類的所有抽象方法舶掖。

kotlin擴展函數(shù)的java調(diào)用方式

kotlin中的擴展函數(shù)是非常方便的,剛開始以為在java中不能夠調(diào)用到kotlin中的擴展函數(shù)尔店,后面發(fā)現(xiàn)不是的眨攘,對于我們定義的擴展函數(shù)類主慰,在java中有相應的使用方式

//KotlinExt.kt
fun Int.dp2px(context: Context?): Int {
    val scale = context?.resources?.displayMetrics?.density?.toInt()
    return (this * (scale ?: 2) + 0.5f).toInt()
}
//java中調(diào)用
KotlinExtKt.dp2px(2, getContext());

我們只需要import相應的kotlinExt文件,然后就可以調(diào)用其中的方法鲫售,但使用方式和kotlin有不一致的地方河哑,對于kt的擴展函數(shù)的接收者,也就是上面的Int龟虎,在java中會被認為是第一個入?yún)ⅲ?如果擴展函數(shù)接受的是普通參數(shù)璃谨,那么這個參數(shù)就直接作為后續(xù)的入?yún)ⅰ?br> 如果擴展數(shù)據(jù)的第二個參數(shù)是lambda表達式,那么有java相應的生成方式:

//KotlinExt.kt
inline fun <T> Boolean.yes(action: () -> T): Boolean {
    if (this) action()
    return this
}
//java中調(diào)用
KotlinExtKt.yes(true, new Function0<Object>() {
                    @Override
                    public Object invoke() {
                        return null;
                    }
                });

上面的Boolean的擴展yes方法鲤妥,接收一個高階函數(shù)佳吞,kt中用lambda表示,而在java中棉安,需要以一個匿名內(nèi)部類的方式替代底扳,

kotlin中內(nèi)部類

在java中,如果定義一個非靜態(tài)類內(nèi)部類贡耽,默認將會持有外部類的引用衷模,經(jīng)常會造成外部類無法被回收,導致內(nèi)存泄漏蒲赂,而kotlin中阱冶,內(nèi)部類默認不會持有外部類的引用,只有添加上inner關鍵字修飾滥嘴,才會持有外部引用木蹬。

kotlin 密封類

kotlin的密封類是java所沒有的,在kotlin中若皱,如果一個類被標明為密封類镊叁,那么其所有的子類都需要在父類中列出,作為密封類的嵌套內(nèi)部類

kotlin中的惰性集合操作

kotlin中一些集合操作走触,比如說map和filter晦譬,對于我們來說是非常方便的,比如說篩選一個人群的年齡大于30的人的名稱互广。

people.map(it.name).filter{it.age > 30}

但是上面這種方式敛腌,在鏈式調(diào)用的鏈足夠長時,將會產(chǎn)生性能問題兜辞,因為鏈式調(diào)用的每一個步驟都會創(chuàng)建一個中間集合迎瞧,用來存儲中間結果,也就是說逸吵,每一個步驟的結果都存儲在另外一個變量中凶硅。所以,kotlin給我們提供了另外一種使用方式扫皱,來避免創(chuàng)建中間對象足绅。也就是惰性集合捷绑。sequencez作為惰性集合操作,可以優(yōu)化map和filter等操作氢妈,將不會生成任何中間對象

people.asSequence().map(people.name).filter(it.startWith("a")).toList()

sequencez會將元數(shù)據(jù)生成一個流式對象粹污,對于集合的每一個元素利用iterator遍歷,執(zhí)行map和filter首量,篩選出符合條件的數(shù)據(jù)壮吩。
惰性集合的操作包含了中間操作和末端操作,中間操作就是轉(zhuǎn)換操作加缘,末端操作就是篩選操作鸭叙,在上面的例子里面,map是中間操作拣宏,filter是末端操作沈贝,如果沒有末端操作,那么勋乾,中間操作也不會執(zhí)行宋下,既然這樣,如果我們末端操作停止了辑莫,中間操作也會停止学歧,也就是說,并不會保證所有的中間操作都能夠執(zhí)行摆昧。

butterknife庫的使用

在java中撩满,butterknife庫是一個眾所周知的代替findViewId操作的庫,如果我們直接在kotlin中想要使用butterknife這個庫绅你,那還是需要一些額外的操作的。

引入KotterKnife或者自己提供extension

這個是butterknife作者提供的另外一個kotlin版本的替代庫昭躺。使用方式如下:

val updateTime by bind<TextView>(R.id.update_time)

雖然我沒看KotterKnife內(nèi)部實現(xiàn)忌锯,但是應該跟我們自己提供擴展函數(shù)的實現(xiàn)方式是一樣的,我們可以通過自己提供擴展函數(shù)來設置做這些操作:

fun <T : View> Activity.bind(@IdRes idRes: Int): Lazy<T> {
    return lazy { findViewById<T>(idRes) }
}

fun <T : View> View.bind(@IdRes idRes: Int): Lazy<T> {
    return lazy { findViewById<T>(idRes) }
}

fun <T : View> android.support.v7.widget.RecyclerView.ViewHolder.bind(@IdRes idRes: Int): Lazy<T> {
    return lazy { this.itemView.findViewById<T>(idRes) }
}

fun <T : View> Fragment.bind(@IdRes idRes: Int): Lazy<T?> {
    return lazy { this.view?.findViewById<T>(idRes) }
}

這個擴展數(shù)據(jù)其實就是代替我們執(zhí)行findViewById操作领炫,雖然我們是在初始化的時候定義了View的對象偶垮,但是它并不會馬上執(zhí)行,lazy關鍵字修飾的對象將會等到使用時再執(zhí)行相應方法帝洪。也就是說似舵,這個findViewById將會在setContentView之后執(zhí)行,因為我們使用這個對象肯定是在其之后的葱峡。

仍然使用butterknife

其實在kotlin中砚哗,我們還是可以使用butterknife的,只是我們需要將butterknife的注解解釋器替換為kotlin annotation Processor tool砰奕,這樣蛛芥,在kt文件中就能夠使用butterknife的注解了提鸟,我們不需要擔心會對之前的注解產(chǎn)生影響,因為kapt是兼容了annotationProcessor的仅淑。

annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0'
====>
kapt 'com.jakewharton:butterknife-compiler:8.4.0'

替換了kapt之后称勋,就可以進行第二步了,在kt中利用laterinit修飾對象,來保證view對象可以在通過butterknife庫賦值

 @BindView(R.id.user_v_layout)
    lateinit var vLayout: ImageView
    @BindView(R.id.comment_user_icon)
    lateinit var userIconIV: ImageView
    @BindView(R.id.comment_user_name)
    lateinit var userNameTV: TextView
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末涯竟,一起剝皮案震驚了整個濱河市赡鲜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庐船,老刑警劉巖银酬,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異醉鳖,居然都是意外死亡捡硅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人句伶,你說我怎么就攤上這事逻悠。” “怎么了舟铜?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我屯曹,道長,這世上最難降的妖魔是什么惊畏? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任恶耽,我火速辦了婚禮,結果婚禮上颜启,老公的妹妹穿的比我還像新娘偷俭。我一直安慰自己,他們只是感情好缰盏,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布涌萤。 她就那樣靜靜地躺著,像睡著了一般口猜。 火紅的嫁衣襯著肌膚如雪负溪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天济炎,我揣著相機與錄音川抡,去河邊找鬼。 笑死冻辩,一個胖子當著我的面吹牛猖腕,可吹牛的內(nèi)容都是我干的拆祈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼倘感,長吁一口氣:“原來是場噩夢啊……” “哼放坏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起老玛,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤淤年,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜡豹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體麸粮,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年镜廉,在試婚紗的時候發(fā)現(xiàn)自己被綠了弄诲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡娇唯,死狀恐怖齐遵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情塔插,我是刑警寧澤梗摇,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站想许,受9級特大地震影響伶授,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜流纹,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一糜烹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧漱凝,春花似錦景图、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亮蒋。三九已至扣典,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慎玖,已是汗流浹背贮尖。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留趁怔,地道東北人湿硝。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓薪前,卻偏偏與公主長得像,于是被迫代替她去往敵國和親关斜。 傳聞我的和親對象是個殘疾皇子示括,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 正午時光,陽光暖暖痢畜,一絲深深的憂傷爬上心頭垛膝。有一些孤獨,有一些傷感丁稀。 10吼拥,24……生命中一些重要的數(shù)字,讓我對緣...
    健康管理師李建昕閱讀 249評論 0 0
  • 折線圖是最清楚的表達上升线衫、下降凿可、波動等趨勢的圖形。畫折線圖時授账,一定要確保趨勢線比基線粗枯跑,基線比坐標線粗。當把折線和...
    壓壓壓壓寨夫人閱讀 694評論 0 0
  • 今天我和媽媽一起貼獎狀矗积,貼獎狀可有意思啦全肮,媽媽給我貼獎狀我夠不到,爸爸說:媽媽這么矮棘捣,能貼上嗎然后爸爸又貼了一個獎...
    平凡一生123閱讀 600評論 0 0