使用Kotlin優雅的添加Fragment

綜述

在上面文章聊一聊Kotlin擴展函數run,with,let,also和apply的使用和區別中講解Kotlin的幾個擴展函數的使用和區別。那麼在這篇文章中去自己定義一些擴展函數來更加優雅的去將添加Fragment到Activity中。

回顧Fragment使用

在使用Kotlin之前,首先回顧一下在Java中是如何添加一個Fragment到Activity當中的。

FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(frameId, fragment);
transaction.commit();

上面這段代碼是在熟悉不過了,在項目中爲了避免大量的重複書寫上面那段代碼,通常會創建一個ActivityUtil的類,在這個類中寫一個static方法來封裝上面那段代碼。

public static void addFragmentToActivity(FragmentManager manager, Fragment fragment, int frameId) {

    FragmentTransaction transaction = manager.beginTransaction();
    transaction.add(frameId, fragment);
    transaction.commit();

}

這時候在Activity當中便能夠直接使用上面的方法:

ActivityUtil.addFragmentToActivity(
        getSupportFragmentManager(), fragment, R.id.frag_container);

在介紹完使用Java來添加Fragment後,下面就來看一下如何使用Kotlin更優雅的來添加Fragment。

Kotlin添加Fragment

使用Kotlin完成Fragment的天假只需要兩步即可:

消除beginTransaction() and commit()方法

對於Fragment的操作每次都需要beginTransaction()和commit(),如果在開發中少寫了一個commit()方法,或許會花費大量時間進行調試找到問題所在。所以省去beginTransaction()和commit()代碼的書寫還是很有必要的。

在Kotlin中,可以爲FragmentManager類寫一個擴展函數,將一個帶有接收者函數的lambda作爲擴展函數的參數。下面簡單介紹一下相關知識點:

  1. 擴展函數(Extension functions)
    擴展函數能夠向已經存在的類中添加新的函數或屬性,也包含第三方庫或者SDK中的類。在函數內部,可以不使用任何限定符來訪問類的公共函數和屬性,就像這個函數在類的內部一樣。

  2. 高階函數(Higher-Order Functions)
    高階函數是將函數作爲參數,或返回一個函數的函數。可以傳遞函數或者從函數中返回一個函數。

  3. 帶接收者的Lambda函數(Function Literals with Receiver
    可以說是以上兩個的組合,一個高階函數將一個擴展函數作爲它的參數。將lambda表達式中作爲參數傳遞,並且我們可以訪問接收者的函數和屬性,就好像lambda函數在接收者對象的內部一樣。

現在書寫一個FragmentManager的擴展函數,它將一個帶有接受者的Lambda函數作爲傳入的參數,而這個FragmentTransaction就是接收者對象。

inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> Unit) {
    val fragmentTransaction = beginTransaction()
    fragmentTransaction.func()
    fragmentTransaction.commit()
}

上面這段代碼是一個擴展函數,他接收的參數是一個帶有接收者的Lambda函數。這個Lambda函數沒有任何參數並且返回的是Unit。在這個inTransaction擴展函數體內首先調用beginTransaction()獲取FragmentTransaction對象,然後在執行Lambda函數之後執行commit()方法。

那麼就可以通過一下代碼將我們的Fragment添加到Activity當中:

supportFragmentManager.inTransaction {
    add(R.id.frameLayoutContent, fragment)
}

在這裏可以看出來在Lambda函數當中可以直接操作FragmentTransaction中的方法,並且沒有任何的使用限制。因爲這個Lambda函數本身就是FragmentTransaction的一個擴展函數。

在使用上面的擴展函數當中不需要每次再執行beginTransaction()和commit()方法。甚至我們還能夠在inTransaction方法中執行多次操作。

supportFragmentManager.inTransaction {
    remove(fragmentA)    
    add(R.id.frameLayoutContent, fragmentB)
}

現在再次對inTransaction函數進行一次升級,可以將傳入的Lambda函數添加一個返回值,返回FragmentTransaction對象。這樣會使得我們的代碼更加簡潔。

inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
    beginTransaction().func().commit()
}

使用擴展函數來替代ActivityUtil

現在就可以使用上面的inTransaction方法來寫一些FragmentActivity的擴展函數來取代Java中的ActivityUtil類。那麼就以對Fragment的add和replace操作爲例寫兩個FragmentActivity的擴展函數addFragment和replaceFragment。

fun FragmentActivity.addFragment(fragment: Fragment, frameId: Int){
    supportFragmentManager.inTransaction { add(frameId, fragment) }
}


fun FragmentActivity.replaceFragment(fragment: Fragment, frameId: Int) {
    supportFragmentManager.inTransaction{replace(frameId, fragment)}
}

由於這些擴展函數是FragmentActivity的擴展函數。所以在這些擴展函數內部就能夠直接訪問到FragmentActivity中的supportFragmentManager。

使用上面的擴展函數,就可以通過一行代碼在Activity中添加Fragment。

addFragment(fragment, R.id.fragment_container)

replaceFragment(fragment, R.id.fragment_container)

總結

通過上篇文章瞭解了Kotlin一些擴展函數。而在這篇文章中去通過對Fragment添加去了解擴展函數的意義以及對高階函數的使用。當然通過擴展函數也能夠更佳的完善一些SDK中一些不合理的API。還能夠寫出更漂亮簡潔的代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章