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