(译)使用Kotlin的方式添加Fragment
原文地址:https://medium.com/thoughts-overflow/how-to-add-a-fragment-in-kotlin-way-73203c5a450b
1.png本文介绍了利用Kotlin扩展函数的特性在Activity中管理Fragment的方式。
以下是正文
本文来源于StackOverflow的一个回答
在开始使用Kotlin的方式添加Fragment之前,我们先重新看一下使用Java的方式
原始的方式:
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(frameId, fragment);
transaction.commit();
为了避免在每个Activity
中重复这样模板化的代码,我们一般在ActivityUtil
工具类中实现一个静态方法
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);
这样就完了,毫无新意。现在让我们如何使用Kotlin两个步骤把这做的更好。
1.消除beginTransaction()和commit()
不知道你曾经浪费了多少时间来调试你的程序,最后才发现是在Fragment
事务之后忘记调用commit
方法了。
为了消除上述代码,我们实现一个FragmentManager
的扩展函数
,接收一个Lambda表达式作为参数。
我们用到的Kotlin功能的快速介绍
扩展函数可以为已经存的类添加新的方法或属性,即使类来自其他库或者SDK的。在方法内我们可以直接访问该类的public方法和属性,并且不需要修饰语就好像方法存在类里面一样。(注意:实际上
扩展函数
并没有修改已经存在的类而是创建了一个静态方法)高阶函数是以函数为参数或者返回值的函数,我们可以像传递数据一样在函数中传入或者返回函数。
Lambda表达式接收器(函数字面量接收器)是上面两者的结合——一个以指定接收器的扩展函数为参数的高阶函数。所以在我们传递的Lambda表达式中我们可以直接访问接收器的公共方法和属性,就好像在接收器内部一样。
这就是FragmentManager
的扩展函数,接收一个Lambda表达式接收器
作为参数,FragmentTransaction
作为接收器
inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> Unit) {
val fragmentTransaction = beginTransaction()
fragmentTransaction.func()
fragmentTransaction.commit()
}
这里参数为FragmentTransaction
的扩展函数,函数没有参数并且返回值为Unit
.我们在调用beginTransaction()
之后调用该函数,最后调用commit()
提交事务.
现在在Activity中添加Fragment我们可以这样调用
supportFragmentManager.inTransaction {
add(R.id.frameLayoutContent, fragment)
}
需要说明的是在Lambda表达式中我们调用FragmentTransaction的方法如add
或者remove
时并没有使用修饰符,因为这是对FragmentTransaction的扩展函数.
使用上面的扩展函数,我们在添加或者替换Fragment时就不需要调用beginTransaction()
和commit()
了.我们甚至可以在inTransaction
代码块中调用多个方法,每个方法都运行在Fragment的事务中.(此处不太确定是所有方法运行在一个事务中还是每个方法在单独的事务中)
supportFragmentManager.inTransaction {
remove(fragmentA)
add(R.id.frameLayoutContent, fragmentB)
}
2017年8月24日更新:Dai在评论中建议我们可以完善一下inTransaction
,让lambda表达式返回FragmentTransaction
:
inline fun FragmentManager.inTransaction(func: FragmentTransaction.() -> FragmentTransaction) {
beginTransaction().func().commit()
}
2.使用扩展函数代替ActivityUtil
接下来,我们看一下使用AppCompatActivity的扩展函数比ActivityUtil工具类好在哪里
我们可以实现AppCompatActivity的扩展函数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
本身的扩展函数,我们可以在函数内部直接访问supportFragmentManager
.
使用上面的扩展函数,我们在Activity
中添加或者替换Fragment
可以一行代码实现,不需要任何修饰符:
addFragment(fragment, R.id.fragment_container)
replaceFragment(fragment, R.id.fragment_container)
这里没有使用额外的修饰符调用这些函数,看上去好像Android SDK本身提供了这些函数.
使用Kotlin我们弥补了Android API的不足,并且实现了一种更加简洁,易读,不容易出错的添加Fragment的代码.
不仅如此,使用Kotlin的扩展函数,高阶函数,Lambda表达式接收器可以为你的工程创建一个优雅的DSL(领域特定语言).