}
scaleType = ImageView.ScaleType.FIT_XY
setImageResource(R.drawable.user_portrait_gender_female)
}.also { addView(it) }
}.also { addView(it) }
RelativeLayout(this@Factory2Activity2).apply {
layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
topMargin = 10f.dp()
}
setPadding(0, 0, 10f.dp(), 10f.dp())
TextView(this@Factory2Activity2).apply {
layoutParams =
RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT)
.apply {
addRule(RelativeLayout.ALIGN_PARENT_END, RelativeLayout.TRUE)
}
text = “2020.04.30”
}.also { addView(it) }
}.also { addView(it) }
}.also { addView(it) }
}.also { addView(it) }
}.also { addView(it) }
View(this@Factory2Activity2).apply {
layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 1f.dp())
setBackgroundColor(Color.parseColor("#eeeeee"))
}.also { addView(it) }
RelativeLayout(this@Factory2Activity2).apply {
layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
topMargin = 40f.dp()
}
LinearLayout(this@Factory2Activity2).apply {
layoutParams = RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT).apply {
addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE)
}
orientation = LinearLayout.HORIZONTAL
Button(this@Factory2Activity2).apply {
layoutParams =
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
rightMargin = 20f.dp()
gravity = Gravity.LEFT
}
setBackgroundResource(R.drawable.bg_orange_btn)
text = “cancel”
}.also {
addView(it)
}
Button(this@Factory2Activity2).apply {
layoutParams =
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
leftMargin = 20f.dp()
gravity = Gravity.RIGHT
}
setBackgroundResource(R.drawable.bg_orange_btn)
text = “OK”
}.also { addView(it) }
}.also { addView(it) }
}.also { addView(it) }
}
}
用伪代码描述上述代码,结构就是这样的:
容器控件.apply {
子控件.apply {
//设置控件属性
}.also { addView(it) }
}
代码又臭又长又冗余,完全没有可读性。若要微调其中显示宝石的控件,你可以试下,反正我是找不到那个控件了。
但跑了一下测试代码,惊喜地发现构建布局的平均耗时只有 1.32 ms,时间是静态布局的 1/20 。
一开始我以为是嵌套布局导致特别耗时,于是用ConstraintLayout
将嵌套扁平化,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=“http://schemas.android.com/apk/res/android”
xmlns:app=“http://schemas.android.com/apk/res-auto”
android:layout_width=“match_parent”
android:layout_height=“match_parent”>
</androidx.constraintlayout.widget.ConstraintLayout>
这次做到了零嵌套,带着期望重新运行了一遍代码。但解析布局耗时丝毫没有变化。。。好吧
既然静态布局和动态布局有这么大的性能差距,那就改善一下动态布局代码的可读性!!
DSL
DSL 是改善构建代码可读性的利器!
DSL = domain specific language,即“特定领域语言”,与它对应的一个概念叫“通用编程语言”,通用编程语言有一系列完善的能力来解决几乎所有能被计算机解决的问题,像 Java 就属于这种类型。而特定领域语言只专注于特定的任务,比如 SQL 只专注于操纵数据库,HTML 只专注于表述超文本。
既然通用编程语言能够解决所有的问题,那为啥还需要特定领域语言?因为它可以使用比通用编程语言中等价代码更紧凑的语法来表达特定领域的操作。比如当执行一条 SQL 语句时,不需要从声明一个类及其方法开始。
更紧凑的语法意味着更简洁的 API。应用程序中每个类都提供了其他类与之交互的可能性,确保这些交互易于理解并可以简洁地表达,对于软件的可维护性至关重要。
DSL 有一个普通API不具备特征:DSL 具有结构。而带接收者的lambda
使得构建结构化的 API 变得容易。
带接收者的 lambda
它是一种特殊的 lambda,是 kotlin 中特有的。可以把它理解成“为接收者声明的一个匿名扩展函数”。(扩展函数是一种在类体外为类添加功能的特性)
带接收者的lambda的函数体除了能访问其所在类的成员外,还能访问接收者的所有非私有成员,这个特性是它能够轻松地构建结构。
当带接收者的 lambda 配合高阶函数时,构建结构化的 API 就变得易如反掌。
高阶函数
它是一种特殊的函数,它的参数或者返回值是另一个函数。
比如集合的扩展函数filter()
就是一个高阶函数:
//filter的参数是一个带接收的lambda
public inline fun Iterable.filter(predicate: (T) -> Boolean): List {
return filterTo(ArrayList(), predicate)
}
可以使用它来过滤集合中的元素:</