application

  • Null type safety

    Kotlin introduced nullable types (using? Flag), which eliminates the possibility of nullable types calling methods directly at compile time.

    var a: String = "abc"
    a = null // Error compiling
    
    var b: String? = "abc"
    b = null // ok
    
    val l = a.length
    
    val l = b.length // Error: variable "b" may be emptyval l = b? .length ? :0
    Copy the code
  • Chain calls

    Using Kotlin’s let, apply, and takeIf methods to organize your code in chained calls, you can break up a large string of logic into chunks.

    File(url).takeIf { it.exists() } ? .let { JSONObject(NetworkUtils.postFile(SERVER_URL, url)) }? .takeIf { it.optString("message") = ="success" }
            ?.let {
                post(it.optString("result"}))? : mHandler.post { view? .onFail() }Copy the code
  • The default parameters

    A normal method with default parameters is not callable by Java because Kotlin doesn’t generate multiple methods with default parameters. Instead, he adds a few extra parameters to the method to record how many parameters the caller passes, with JvmOverloads added to generate multiple methods for Java to call. And the Kotlin call method can specify parameter names.

    class CustomLayout @JvmOverloads constructor(
            context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : FrameLayout(context, attrs, defStyleAttr), LifeCycleMonitor {
        // pass
    }
    Copy the code
  • Extension methods

    Extensions are used less often in projects, but many of the syntactic sugar Kotlin provides is implemented using extensions, such as forEach, let, and the like. Extension methods work by generating a static method.

    // _collections.kt extension methods
    /** * Performs the given [action] on each element. */
    @kotlin.internal.HidesMembers
    public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
        for (element in this) action(element)
    }
    Copy the code
  • Operator overloading

    Kotlin will translate some common expressions into method calls. The most common ones are to translate list[0] to list.get(0) and map[0] = someObject to map.set(0, someObject). In fact, both expressions can be used by Any class that implements the operator Fun get(a: Any) : Any and operator Fun set(a: Any, b: Any) methods.

    // Operator overloading is ubiquitous in Kotlin's syntax, as this example illustrates
    for (i in 1.10) {
        // pass
    }
    // How does this work? Corresponds to the rangeTo method, and the expression in corresponds to the CONTAINS method
     
    // In the Int class in primities.kt
     /** Creates a range from this value to the specified [other] value. */
    public operator fun rangeTo(other: Int): IntRange
     
    // Inside the IntRange class, we can find in corresponding to the method call contains
    public class IntRange(start: Int, endInclusive: Int) : IntProgression(start, endInclusive, 1), ClosedRange<Int> {
        override val start: Int get(a) = first
        override val endInclusive: Int get(a) = last
     
        override fun contains(value: Int): Boolean = first <= value && value <= last
    Copy the code

    The operator in Kotlin overrides the mapping between all expressions and method calls

  • No longer use findViewById

    Add the apply plugin to build.gradle :’ kotlin-android-Extensions’ to replace the View object with the View ID.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        iv_feedback.setOnClickListener(this)
        iv_back.setOnClickListener(this)
        btn_feedback.setOnClickListener(this)
    Copy the code

    The principle behind this is that Kotlin automatically generates findViewById code for activities, fragments, and custom views. Kotlin uses a map to cache each View it finds, Avoid calling findViewById again every time a View is called, but note that there is no cache when retrieving a child View from view. id. So in the ViewHolder of RecyclerView, we use a property to store a child View of ItemView.

    // The logic in the Activity
    public View _$_findCachedViewById(int var1) {
       if(this._$_findViewCache == null) {
          this._$_findViewCache = new HashMap();
       }
     
       View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1));
       if(var2 == null) {
          FindViewById is called in the Fragment code, so calling methods by ID needs to be used after the onCreateView life cycle
          var2 = this.findViewById(var1);
          this._$_findViewCache.put(Integer.valueOf(var1), var2);
       }
     
       return var2;
    }
    
    // The ViewHolder of RecyclerView uses a property to store a child View of ItemView
    private val mLabelImage = itemView.label_image
    private val mLabelType = itemView.label_type
    Copy the code
  • Some changes related to attributes

  1. Bring their own getter/setter

    Properties in the Kotlin class come with getters/setters, and access permissions can be changed, or get/set methods can be overridden

     var someString : String
        get(a) = "this${toString()}"
        protected set(value) {
            Log.e(TAG, "setValue$value")
            field = value
        }
    Copy the code
  2. You can define it in a class declaration

    open class Message(val id: Long, val type: Int, val time: Long, val status : Int)
    Copy the code
  3. LateInit and by lazy

Lateinit and by lazy can be used to delay initialization for objects of non-empty type that are not assigned in constructors.

pit

Java calls to the Kotlin method space-time type are no longer safe

When a Java call to kotlin’s method is made, non-nullable arguments passed to Kotlin by an empty object throw an exception, but Kotlin cannot tell if an object passed by Java is likely to be empty, so the compiler does not raise an exception. This pit cannot be ignored in the process of converting a Java project into a Kotlin project.

More and more

coroutines

Anko Layouts replace XML

verticalLayout {
   val name = editText()
   button("Say Hello") {
       onClick { toast("Hello, ${name.text}!")}}}Copy the code