Following on from the previous article, which introduced the Kotlin features used in the project, this article continues to sort out the features used in the current project.

1. Apply and run functions

The with, apply, and run functions are all functions in the Kotlin standard library. With was introduced in the first article.

1.1 the apply function

The apply function refers to an object that can be referred to by this within a function block and returns the value of the object itself. In chained calls, consider using it without breaking the chain.

/** * Calls the specified function [block] with `this` value as its receiver and returns `this` value. */
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T. () -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}
Copy the code

Here’s an example:

/** * Created by tony on 2018/4/26. */
object Test {

    @JvmStatic
    fun main(args: Array<String>) {

        val result ="Hello".apply {


            println(this+" World")

            this+" World"
        }

        println(result)
    }
}
Copy the code

Execution result:

Hello World
Hello
Copy the code

The first string is printed in the closure, and the second string is the result of result, which is still “Hello.”

1.2 run function

The run function is similar to the apply function, but the run function returns the value of the last row.

/** * Calls the specified function [block] with `this` value as its receiver and returns its result. */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T. () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}
Copy the code

Here’s an example:

/** * Created by tony on 2018/4/26. */
object Test {

    @JvmStatic
    fun main(args: Array<String>) {

        val result ="Hello".run {


            println(this+" World")

            this + " World"
        }

        println(result)
    }
}
Copy the code

Execution result:

Hello World
Hello World
Copy the code

The first string is printed in the closure, and the second string is the result of result, which returns the value of the last line in the closure, so “Hello World” is also printed.

1.3 Use in projects

In the feedback page of the App, you need to input the email, theme and content to complete the submission of the feedback button.

It was originally written like this:

        if(viewModel.email.value!! .isEmpty()) { toast(resources.getString(R.string.you_have_not_completed_the_email_address)).show()return@onClickRight
        }
        if(! Util.checkEmail(viewModel.email.value!!) ) { toast(resources.getString(R.string.the_email_format_you_have_filled_is_incorrect)).show()return@onClickRight
        }
        if(viewModel.subject.value!! .isEmpty()) { toast(resources.getString(R.string.you_have_not_completed_the_feedback_subject)).show()return@onClickRight
        }
        if(viewModel.content.value!! .isEmpty()) { toast(resources.getString(R.string.you_have_not_completed_the_details)).show()return@onClickRight
        }
Copy the code

Change to use only the apply function

       viewModel.apply {

            if(email.value!! .isEmpty()) { toast(resources.getString(R.string.you_have_not_completed_the_email_address)).show()return@onClickRight
            }
            if(! Util.checkEmail(email.value!!) ) { toast(resources.getString(R.string.the_email_format_you_have_filled_is_incorrect)).show()return@onClickRight
            }
            if(subject.value!! .isEmpty()) { toast(resources.getString(R.string.you_have_not_completed_the_feedback_subject)).show()return@onClickRight
            }
            if(content.value!! .isEmpty()) { toast(resources.getString(R.string.you_have_not_completed_the_details)).show()return@onClickRight}}Copy the code

It’s not cool enough. You can use it together with the run and apply functions

        viewModel.email.run {

            if(value!! .isEmpty()) { toast(resources.getString(R.string.you_have_not_completed_the_email_address)).show()return@onClickRight
            }
            if(! Util.checkEmail(value!!) ) { toast(resources.getString(R.string.the_email_format_you_have_filled_is_incorrect)).show()return@onClickRight
            }

            viewModel
        }.subject.run {

            if(value!! .isEmpty()) { toast(resources.getString(R.string.you_have_not_completed_the_feedback_subject)).show()return@onClickRight
            }

            viewModel
        }.content.apply {

            if(value!! .isEmpty()) { toast(resources.getString(R.string.you_have_not_completed_the_details)).show()return@onClickRight}}Copy the code

2. The data class

Kotlin’s data class is somewhat similar to Scala’s case class.

The following Java Bean code

/** * Created by tony on 2018/4/27. */
public class User {

    public String userName;
    public String password;
}
Copy the code

Is equivalent to

data class User (var userName: String? = null.var password: String? = null)
Copy the code

You can see how using data Classes can simplify Java Bean classes. Our App adopts the MVVM architecture, so all corresponding Model classes use data class.

No need to use findViewById or Butterknife

You can do this using the Kotlin Android Extensions plugin, which is part of the Kotlin plugin. You do not need to install a separate plugin.

We add the plugin to the build.gradle of each module and you can use it.

apply plugin: 'kotlin-android-extensions'
Copy the code

The id in the layout file can be used directly in the code. First of all, according to the import kotlinx. Android. Synthetic. Main. Layout file name * mode import.

For example, MainActivity, whose layout file is activity_main.xml, is imported as follows

import kotlinx.android.synthetic.main.activity_main.*
Copy the code

Then the id of the control in activity_main.xml can be used directly in the MainActivity without using findViewById or Butterknife. Isn’t it very convenient?

4. Click the buried point processing of the event

App burial point, use their own home product – magic window SDK to do the event of the burial point.

If you are developing your App in Java, you can use AOP to implement embedding. Since our App is written by Kotlin, Kotlin can simplify the click of the event into the following form

        view.setOnClickListener {
             ....
        }
Copy the code

This is a simplified lambda expression, so I’m going to do it the old-fashioned way.

Common ways to use Kotlin:

View.setonclicklistener {trackAgent.currentevent ().customEvent(eventName).... }Copy the code

or

View.setonclicklistener {trackAgent.currentevent ().customEvent(eventName, trackMap).... }Copy the code

Later, I wrote a View extension function click, which was later optimized by a colleague. Check out the short book article for an elegant implementation of “Prevent Repeated clicks” using extension functions.

At present, have put the extension function in my Kolin tool library at https://github.com/fengzhizi715/SAF-Kotlin-Utils

At this point, the buried point code looks like this

View.click {trackagent.currentevent ().customEvent(eventName).... }Copy the code

or

View.click {trackagent.currentevent ().customEvent(eventName, trackMap).... }Copy the code

To further optimize the processing, add the extension function clickWithTrack to View specifically for buried point click events.

package cn.magicwindow.core.ext

import android.view.View
import cn.magicwindow.TrackAgent
import com.safframework.ext.clickWithTrigger

/ * * * *@FileName:
 *          cn.magicwindow.core.ext.ViewExt.java
 * @author: Tony Shen
 * @date: * he was 2018-04-24@versionV1.0 < Describes the current version functions > */

fun <T : View> T.clickWithTrack(eventName: String, time: Long = 600, block: (T) -> Unit) = this.clickWithTrigger(time) {

    TrackAgent.currentEvent().customEvent(eventName)
    block(it as T)
}

fun <T : View> T.clickWithTrack(eventName: String, trackMap: HashMap<String, String>, time: Long = 600, block: (T) -> Unit) = this.clickWithTrigger(time) {

    TrackAgent.currentEvent().customEvent(eventName, trackMap)
    block(it as T)
}
Copy the code

At this point, the burial point can be used as follows:

        view.clickWithTrack(key) {
            ....
        }
Copy the code

or

        view.clickWithTrack(key,trackMap) {
            ....
        }
Copy the code

conclusion

Kotlin has a lot of syntactic sugar that you can use to simplify your code and implement functionality more gracefully.

Related articles in this series:

Use Kotlin to efficiently develop Android App(5) the final part

Developing Android Apps efficiently with Kotlin (part 4)

Developing Android Apps efficiently with Kotlin (part 3)

Developing Android Apps efficiently with Kotlin (1)


Java and Android technology stack: weekly updates push original technical articles, welcome to scan the public qr code below and follow, look forward to growing with you and progress together.