原文地址:https://medium.com/thoughts-overflow/how-to-add-a-fragment-in-kotlin-way-73203c5a450b
本文介紹了利用Kotlin擴(kuò)展函數(shù)的特性在Activity中管理Fragment的方式。
以下是正文
本文來源于StackOverflow的一個回答
在開始使用Kotlin的方式添加Fragment之前,我們先重新看一下使用Java的方式
原始的方式:
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(frameId, fragment);
transaction.commit();
為了避免在每個Activity
中重復(fù)這樣模板化的代碼构拳,我們一般在ActivityUtil
工具類中實現(xiàn)一個靜態(tài)方法
public static void addFragmentToActivity(FragmentManager manager, Fragment fragment, int frameId) {
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(frameId, fragment);
transaction.commit();
}
然后我們在Activity
中調(diào)用這個靜態(tài)方法
ActivityUtil.addFragmentToActivity(
getSupportFragmentManager(), fragment, R.id.frag_container);
這樣就完了,毫無新意≡柑現(xiàn)在讓我們?nèi)绾问褂肒otlin兩個步驟把這做的更好女责。
1.消除beginTransaction()和commit()
不知道你曾經(jīng)浪費了多少時間來調(diào)試你的程序榨乎,最后才發(fā)現(xiàn)是在Fragment
事務(wù)之后忘記調(diào)用commit
方法了丁屎。
為了消除上述代碼鲁沥,我們實現(xiàn)一個FragmentManager
的擴(kuò)展函數(shù)
,接收一個Lambda表達(dá)式作為參數(shù)呼股。
我們用到的Kotlin功能的快速介紹
擴(kuò)展函數(shù)可以為已經(jīng)存的類添加新的方法或?qū)傩裕词诡悂碜云渌麕旎蛘逽DK的画恰。在方法內(nèi)我們可以直接訪問該類的public方法和屬性彭谁,并且不需要修飾語就好像方法存在類里面一樣。(注意:實際上
擴(kuò)展函數(shù)
并沒有修改已經(jīng)存在的類而是創(chuàng)建了一個靜態(tài)方法)高階函數(shù)是以函數(shù)為參數(shù)或者返回值的函數(shù)允扇,我們可以像傳遞數(shù)據(jù)一樣在函數(shù)中傳入或者返回函數(shù)缠局。
Lambda表達(dá)式接收器(函數(shù)字面量接收器)是上面兩者的結(jié)合——一個以指定接收器的擴(kuò)展函數(shù)為參數(shù)的高階函數(shù)。所以在我們傳遞的Lambda表達(dá)式中我們可以直接訪問接收器的公共方法和屬性考润,就好像在接收器內(nèi)部一樣狭园。
這就是FragmentManager
的擴(kuò)展函數(shù),接收一個Lambda表達(dá)式接收器
作為參數(shù),FragmentTransaction
作為接收器
inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> Unit) {
val fragmentTransaction = beginTransaction()
fragmentTransaction.func()
fragmentTransaction.commit()
}
這里參數(shù)為FragmentTransaction
的擴(kuò)展函數(shù),函數(shù)沒有參數(shù)并且返回值為Unit
.我們在調(diào)用beginTransaction()
之后調(diào)用該函數(shù),最后調(diào)用commit()
提交事務(wù).
現(xiàn)在在Activity中添加Fragment我們可以這樣調(diào)用
supportFragmentManager.inTransaction {
add(R.id.frameLayoutContent, fragment)
}
需要說明的是在Lambda表達(dá)式中我們調(diào)用FragmentTransaction的方法如add
或者remove
時并沒有使用修飾符,因為這是對FragmentTransaction的擴(kuò)展函數(shù).
使用上面的擴(kuò)展函數(shù),我們在添加或者替換Fragment時就不需要調(diào)用beginTransaction()
和commit()
了.我們甚至可以在inTransaction
代碼塊中調(diào)用多個方法,每個方法都運行在Fragment的事務(wù)中.(此處不太確定是所有方法運行在一個事務(wù)中還是每個方法在單獨的事務(wù)中)
supportFragmentManager.inTransaction {
remove(fragmentA)
add(R.id.frameLayoutContent, fragmentB)
}
2017年8月24日更新:Dai在評論中建議我們可以完善一下inTransaction
,讓lambda表達(dá)式返回FragmentTransaction
:
inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
beginTransaction().func().commit()
}
2.使用擴(kuò)展函數(shù)代替ActivityUtil
接下來,我們看一下使用AppCompatActivity的擴(kuò)展函數(shù)比ActivityUtil工具類好在哪里
我們可以實現(xiàn)AppCompatActivity的擴(kuò)展函數(shù)addFragment
和replaceFragment
:
fun AppCompatActivity.addFragment(fragment: Fragment, frameId: Int){
supportFragmentManager.inTransaction { add(frameId, fragment) }
}
fun AppCompatActivity.replaceFragment(fragment: Fragment, frameId: Int) {
supportFragmentManager.inTransaction{replace(frameId, fragment)}
}
由于這是對AppCompatActivity
本身的擴(kuò)展函數(shù),我們可以在函數(shù)內(nèi)部直接訪問supportFragmentManager
.
使用上面的擴(kuò)展函數(shù),我們在Activity
中添加或者替換Fragment
可以一行代碼實現(xiàn),不需要任何修飾符:
addFragment(fragment, R.id.fragment_container)
replaceFragment(fragment, R.id.fragment_container)
這里沒有使用額外的修飾符調(diào)用這些函數(shù),看上去好像Android SDK本身提供了這些函數(shù).
使用Kotlin我們彌補(bǔ)了Android API的不足,并且實現(xiàn)了一種更加簡潔,易讀,不容易出錯的添加Fragment的代碼.
不僅如此,使用Kotlin的擴(kuò)展函數(shù),高階函數(shù),Lambda表達(dá)式接收器可以為你的工程創(chuàng)建一個優(yōu)雅的DSL(領(lǐng)域特定語言).