记录 Kotlin 实践的一些好建议
目录
- 注释
- 函数式接口
- 高阶函数
- 扩展函数
注释
Java:
/**
* @see AdVideoUserInfoContainerData#type
*/
public Builder type(int type) {
userInfoData.type = type;
return this;
}
/** 事件配置, 对应于 {@link FeedAdLottieRepoInfo#name 属性} */
public String lottieConfig;
Kotlin:
/**
* 由[CountDownType.type] mapTo [CountDownType]
* 避免了使用 when(type) 写 else 了
*/
private fun type2Enum(type: () -> String): CountDownType {
return CountDownType.values().firstOrNull {
it.type == type()
} ?: CountDownType.CIRCLE
}
Kotlin 可以使用内联标记来引用类、方法、属性等,这比 Java 中的 @see、@link 更加易用。
文档:kotlinlang.org/docs/kotlin…
函数式接口
非函数式接口:
internal interface ICountDownCallback {
/**
* 倒计时完成时回调
*/
fun finish()
}
internal fun setCountDownCallback(callback: ICountDownCallback) {
// ignore
}
internal fun show() {
setCountDownCallback(object : ICountDownCallback {
override fun finish() {
TODO("Not yet implemented")
}
})
}
函数式接口:
internal fun interface ICountDownCallback {
/**
* 倒计时完成时回调
*/
fun finish()
}
internal fun setCountDownCallback(callback: ICountDownCallback) {
// ignore
}
internal fun show() {
setCountDownCallback {
TODO("Not yet implemented")
}
}
函数式接口也被称为单一抽象方法(SAM)接口,使用函数式接口可以使代码更加简洁,富有表现力。
对于 Java 的接口,比如 View.OnClickListener,它在使用的时候可以直接转 lambda 使用的,只有是 kotlin 的单一抽象方法,需要加 fun 关键字标示它为函数式接口。
文档:kotlinlang.org/docs/fun-in…
高阶函数
如果对象的初始化比较麻烦,可以使用高阶函数,让代码更加流畅:
// 定义
open fun attachToViewGroup(
viewGroup: ViewGroup,
index: Int = -1,
lp: () -> MarginLayoutParams = {
MarginLayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
)
}
) {
(this.parent as? ViewGroup)?.removeView(this)
viewGroup.addView(this, lp.invoke())
}
// 使用
override fun attachToViewGroup(viewGroup: ViewGroup, index: Int, lp: () -> MarginLayoutParams) {
super.attachToViewGroup(viewGroup, index) {
MarginLayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
).apply {
leftMargin = 14.px(context)
topMargin = 44.px(context)
}
}
}
如果参数的获取比较复杂,代码比较长,有不少判断逻辑,也可以使用高阶函数:
// 定义
fun getCountDownViewByType(context: Context, type: () -> String = { "0" }) {
// ignore
}
// 使用
countDownView = CountDownType.getCountDownViewByType(this) {
rewardVideoCmdData.cmdPolicyData?.countDownType ?: ""
}
如果方法的返回值是一个状态值,然后根据状态值去做相关逻辑处理。这种情况下,其实我们想要的是一个行为,比如代码中充斥着大量的数据解析、校验等逻辑,我们也可以是使用高阶函数重构:
// 重构之前
/**
* 校验数据有效(校验标题和按钮有一个不为空,就可以展示 Dialog)
*/
fun checkValid(): Boolean {
return !dialogTitle.isNullOrEmpty() || !buttonList.isNullOrEmpty()
}
private fun bindData() {
rewardData = RewardDialogData(arguments?.getString(EXTRA_REWARD_DATA) ?: "")
// 弹窗数据不合法,就不需要展示 dialog 了
if (rewardData == null || !rewardData!!.checkValid()) {
dismiss()
return
}
// 更新字体颜色等
updateSkin()
}
// 重构之后
/**
* 数据校验失败,执行 [fail] 函数
*/
internal inline fun RewardDialogData?.checkFailed(fail: () -> Unit) {
this?.let {
if (dialogTitle.isNullOrEmpty() && buttonList.isNullOrEmpty()) {
fail()
}
} ?: fail()
}
private fun bindData() {
rewardData = RewardDialogData(arguments?.getString(EXTRA_REWARD_DATA) ?: "")
// 弹窗数据不合法,就不需要展示 dialog 了
rewardData?.checkFailed {
dismiss()
return
}
// 更新字体颜色等
updateSkin()
}
kotlin 标准库里面也是有非常多的高阶函数的,比如作用域函数(let、apply、run等等),除此之外,还有一些集合类的标准库函数:
// filter
fun showCharge() {
adMonitorUrl?.filter {
!it.showUrl.isNullOrEmpty()
}?.forEach {
ParallelCharge.charge(it.showUrl)
}
}
// forEachIndexed
list.forEachIndexed { index, i ->
// ignore
}
文档:kotlinlang.org/docs/lambda…
扩展函数
// 比较不流畅的写法
val topImgUrl = rewardData?.topImg
if (topImgUrl.isNullOrBlank()) {
topImg.visibility = View.GONE
} else {
topImg.hierarchy?.useGlobalColorFilter = false
topImg.visibility = View.VISIBLE
topImg.setImageURI(topImgUrl)
}
// 使用局部返回标签
topImg.apply {
if (topImgUrl.isNullOrEmpty()) {
visibility = View.GONE
return@apply
}
hierarchy?.useGlobalColorFilter = false
setImageURI(topImgUrl)
visibility = View.VISIBLE
}
/**
* 校验 View 可见性
*
* @return [predicate] false: GONE;true: VISIBLE
*/
internal inline fun <reified T : View> T.checkVisible(predicate: () -> Boolean): T? {
return if (predicate()) {
visibility = View.VISIBLE
this
} else {
visibility = View.GONE
null
}
}
// 使用扩展函数
topImg.checkVisible {
!topImgUrl.isNullOrEmpty()
}?.run {
hierarchy?.useGlobalColorFilter = false
setImageURI(topImgUrl)
}
作者:Omooo
链接:https://juejin.cn/post/7029673754309427207
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。