这是一篇辅助文章,为了辅助大家理解后面的文章,先前先简单的阐述下kotlin的DSL。
DSL是什么
DSL指的是特定领域语言,利用kotlin的DSL语言,我们可以写成更加整洁的代码,是代码的可阅读行大幅度提升。基本的概念以及好处我就不再重复阐述了,网上已经有很多类似的文章了,我就通过具体的代码示例进行展示好了。
kotlin DSL代码长什么样
EditText
我还是从最常见EditText
的TextWatcher
说起。
在Java
中当我们需要添加文本输入监听的的时候,是如下的写法:
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
但是往往有时,我们只需要afterTextChanged
监听,并不需要其他两个,但由于接口的限制,我们不得不全部写出将其实现。导致书写体验和阅读体验下降。
那么在kotlin
中我们可以骚操作:
editText.onTextChange {
afterTextChanged { s ->
}
}
肯定有小伙伴,是这个表情:
那么这是如何实现的呢,首先,自定义个类,继承TextWatcher
:
class TextWatcherDsl : TextWatcher {
private var afterTextChanged: ((s: Editable?) -> Unit)? = null
private var beforeTextChanged: ((s: CharSequence?, start: Int, count: Int, after: Int) -> Unit)? =
null
private var onTextChanged: ((s: CharSequence?, start: Int, before: Int, count: Int) -> Unit)? =
null
override fun afterTextChanged(s: Editable?) {
afterTextChanged?.invoke(s)
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
beforeTextChanged?.invoke(s, start, count, after)
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
onTextChanged?.invoke(s, start, before, count)
}
fun afterTextChanged(after: (s: Editable?) -> Unit) {
afterTextChanged = after
}
fun beforeTextChanged(before: (s: CharSequence?, start: Int, count: Int, after: Int) -> Unit) {
beforeTextChanged = before
}
fun onTextChanged(onChanged: (s: CharSequence?, start: Int, before: Int, count: Int) -> Unit) {
onTextChanged = onChanged
}
}
这里面涉及到kotlin
的参数方法内容(即:方法可以直接作为参数传递进),不懂自行百度,不再讲解。
接下来,来实现一个DSL的扩展方法:
inline fun EditText.onTextChange(textWatcher: TextWatcherDsl.() -> Unit): TextWatcher {
val watcher = TextWatcherDsl().apply(textWatcher)
addTextChangedListener(watcher)
return watcher
}
ok,搞定了,所有的EditText
都具有了onTextChange
方法,监听文本的方法需要什么写什么。
-
1、扩展方法不再具体解释,不是本文重点
-
2、这里的
inline
是指内联方法,即:在编译时期,代码会直接插入掉用处,实际上不是调用外部方法。也就不会造成调用外部方法而导致的性能开销,有兴趣的小伙伴可以百度了学习。
这里需要注意理解下参数TextWatcherDsl.() -> Unit
,TextWatcherDsl
是我们刚刚自定义的类,然后后面跟了一个点
,就是说,这个参数可以接收TextWatcherDsl
类里的所有方法,只要是它里面的方法都可以传递进来。
SharedPreferences
我们再来看下Google官方对于SharedPreferences
的扩展。惯例,我们Java
中使用SP写入数据是这样的:
SharedPreferences sp = getSharedPreferences("demo", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("key1", "value1");
editor.putString("key2", "value2");
editor.apply();
在kotlin
中是这样的:
val sp = getSharedPreferences("demo", Context.MODE_PRIVATE)
sp.edit {
putString("key1", "value1")
putString("key2", "value2")
}
是不是简单易读。
我们来看下官方Google是如何实现的这个方法:
inline fun SharedPreferences.edit(
commit: Boolean = false,
action: SharedPreferences.Editor.() -> Unit
) {
val editor = edit()
action(editor)
if (commit) {
editor.commit()
} else {
editor.apply()
}
}
是的,没错就这么点。
参数SharedPreferences.Editor
后面跟了一个点
,可以接受SharedPreferences.Editor
中的方法,例如putString
File
上面的写法,会kotlin
的小伙伴应该都见过了。接下来,我来展示下另一种DSL的写法,可能你们会很少用。
这里我操作File文件的方法来展示。这里我不再写java代码。
常规写法
首先我们看一下常规拷贝文件的写法:
fun copyTo(form:File, to: File) {
// 具体操作文件拷贝的代码
}
使用:
copyTo(file1, file2)
这种太常见了,Java里也是如此操作的,不细说了。
kotlin扩展写法
接下来改造下,写成扩展方法:
fun File.copyTo(to: File) {
// 具体操作文件拷贝的代码
}
使用:
file1.copyTo(file2)
看起来好像舒服了那么一点
终极写法
infix fun File.copyTo(to: File) {
// 具体操作文件拷贝的代码
}
使用:
file1 copyTo file2
注意看扩展方法前面多了一个infix
来修饰方法,是不是非常接近了我们人类说话时的语言方式。
你们的表情是这样的:
类似的方法,在anko
库中中也有很多地方使用,多去阅读源码就会发现。
本次的简介就到此为此,希望通过直接的代码展示,能让各位找到些感觉