This is a supplementary article. To help you understand the following articles, I first briefly explained Kotlin’s DSL.
What is a DSL
DSLS are domain-specific languages, and with Kotlin’s DSL language, we can write much cleaner code, with much more readable lines of code. I won’t go over the basic concepts and benefits. There are plenty of articles on the web, so I’ll show you some code examples.
What does kotlin DSL code look like
EditText
I’ll start with the TextWatcher, the most common EditText.
In Java, when we need to add a text input listener, we write it like this:
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) {}});Copy the code
Sometimes, however, we only need afterTextChanged to listen, not the other two, but we have to write them all out because of interface limitations. The experience of writing and reading deteriorates.
So in Kotlin we can do:
editText.onTextChange {
afterTextChanged { s ->
}
}
Copy the code
There must be some friends, is this look:
So how does this work? First, define a class that extends from TextWatcher:
class TextWatcherDsl : TextWatcher {
private var afterTextChanged: ((s: Editable?) -> Unit)? = null
private varbeforeTextChanged: ((s: CharSequence? , start:Int, count: Int, after: Int) - >Unit)? =
null
private varonTextChanged: ((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
}
}
Copy the code
This involves kotlin’s parameter method content (that is, methods can be passed directly as parameters), do not understand their own baidu, no longer explain.
Next, implement a DSL extension method:
inline fun EditText.onTextChange(textWatcher: TextWatcherDsl. () -> Unit): TextWatcher {
val watcher = TextWatcherDsl().apply(textWatcher)
addTextChangedListener(watcher)
return watcher
}
Copy the code
Ok, we’re done, all EditText has an onTextChange method, so the method that listens to the text writes whatever it needs.
-
1. Extension methods are not specifically explained and are not the focus of this article
-
Inline means that at compile time, the code inserts the use directly instead of actually calling an external method. There will be no performance overhead caused by calling external methods. Interested partners can learn from baidu.
TextWatcherDsl.() -> Unit, TextWatcherDsl is the class we just defined, and it’s followed by a dot, that is, this parameter accepts all the methods in the TextWatcherDsl class. Anything that’s in it can be passed in.
SharedPreferences
Let’s take a look at Google’s official extension to SharedPreferences. By convention, we use SP to write data in Java like this:
SharedPreferences sp = getSharedPreferences("demo", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("key1"."value1");
editor.putString("key2"."value2");
editor.apply();
Copy the code
In Kotlin it looks like this:
val sp = getSharedPreferences("demo", Context.MODE_PRIVATE)
sp.edit {
putString("key1"."value1")
putString("key2"."value2")}Copy the code
Is it easy to read?
Let’s take a look at how the official Google approach works:
inline fun SharedPreferences.edit(
commit: Boolean = false,
action: SharedPreferences.Editor. () -> Unit
) {
val editor = edit()
action(editor)
if (commit) {
editor.commit()
} else {
editor.apply()
}
}
Copy the code
Yeah, that’s right. That’s it.
The SharedPreferences.Editor parameter is followed by a dot that accepts methods in SharedPreferences.Editor, such as putString
File
If you know Kotlin, you’ve seen this before. Now, LET me show you another way to write DSL, which you probably don’t use very often.
Here I’ll show it by manipulating File. I’m not going to write Java code here.
Regular writing
First let’s take a look at the usual way to copy a file:
Fun copyTo(form:File, to: File) {Copy the code
Use:
copyTo(file1, file2)
Copy the code
This is all too common, and it’s also done in Java, so I won’t go into detail.
Kotlin extension
Next, the transformation is written as the extension method:
fun File.copyTo(to: File) {
// Specify the code to copy the file
}
Copy the code
Use:
file1.copyTo(file2)
Copy the code
It looks a little better
The ultimate writing
infix fun File.copyTo(to: File) {
// Specify the code to copy the file
}
Copy the code
Use:
file1 copyTo file2
Copy the code
Note that the extension method is preceded by an infix modifier, which is very close to the way we speak.
Your faces look like this:
Similar methods are used in many places in the Anko library, as you will find if you read the source code.
That’s the end of this introduction, and I hope you can get a feel for it through a direct code presentation