1. What is Activity

The easiest attraction is Actuvity, a component that can contain a user interface for interacting with users. An application can contain zero or more activities, but an application that does not contain any activities is invisible to the user.

2. Basic usage of Activity

2.1 Manually Creating an Activity

Click on Empty Activity to create an Activity named FirstActivity

2.2 Creating and loading a Layout

Right-click app/ SRC /main/res ->New->Directory to create a New Directory. Now create a Directory named Layout. Right-click layout ->New->Layout Resource File. The offer pops up a window for a new layout resource file, which we’ll name first_layout. The default root element is LinearLayout.

<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

</LinearLayout>
Copy the code

2.2.1 Adding buttons in the Layout

2.2.2 Loading a layout File

class FirstActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {super.oncreate (savedInstanceState) // Load the layout file heresetContentView(R.layout.first_layout)
    }
}
Copy the code

Each element added to the project generates a resource ID in the R file. Therefore, the id of the layout file has been added to the R file, so you can find the ID of first_layout.xml through r.layout.first_layout. We then pass this value to the setContentView() method.

2.3 Register in the andoirdmanifest.xml file

<? xml version="1.0" encoding="utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".FirstActivity"></activity>
    </application>

</manifest>
Copy the code

As you can see, the Activity registration declaration is placed in the < Application > tag, where the Activity is registered with the < Activity > tag. Specify which activity to register with the name attribute in

, so fill in.firstActivity, preceded by “. Because the outermost layer has already declared the package property, added in place of name. FirstActivity is found by the full class name.

The Activity has been registered after the previous steps, but you can’t run the program yet because you need to configure the Activity, which means you need to specify which Activity to start first. So you need to add the intent-filter tag to the

tag, Then add the intent – filter tag < action android: name = “android. Intent. Action. MAIN” / > and < category The android: name = “android. Intent. The category. The LAUNCHER” / > two lines, the statement can be modified code is as follows:

<? xml version="1.0" encoding="utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.activitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
Copy the code

In this case, FirstActivity becomes the main Activity of the application, which is the FirstActivity to open when you click on the application icon. However, if no Activity is declared as the main Activity in the application, the application can still be installed, but the application is not visible in the launcher. Such programs are often called internally by other applications as third-party services.

Operation effect:

2.4 Use Toast in the program

Toast is an excellent reminder provided by the Adnroid system. It can be used in an application to notify users of short messages that disappear automatically over a period of time and do not take up any screen space.

2.4.1 Define the trigger point for popping up Toast

class FirstActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {super.oncreate (savedInstanceState) // Load the layout file heresetContentView(R.layout.first_layout) val button1: Button = the findViewById (R.i db utton1) for the. SetOnClickListener {/ / using Toast Toast. MakeText (this,"You clicked Button 1", 
                Toast.LENGTH_SHORT).show()
        }
    }
}
Copy the code

FindViewById finds the elements defined in the layout file in the Activity. Because this method returns a generic object that inherits from the View, Kotlin cannot deduce what type of control it is getting. Declare a button explicitly as a button type, then register a listener with setOnClickListener. Clicking on the button will trigger the onClick() method, so write the code logic here. The second parameter is the content of the text displayed, and the third parameter is the duration of the Toast display. After clicking the button, it will have the following effect:

The above code implementation is a control found by findViewById, but it is frequently written when there are too many controls. In Java development, it is impossible to avoid this writing, which has resulted in third-party open source libraries such as ButterKnife, but in Kotlin this problem does not exist. Because Android programs written using Kotlin include the Kotlin-Android-Extensions plug-in in the app/build.gradle file, which automatically generates a variable with the same name based on the ID of the control defined in the layout file, We can use it directly instead of findViewById.

class FirstActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) {super.oncreate (savedInstanceState) // Load the layout file heresetContentView(R.layout.first_layout) // val button1: Button = the findViewById (R.i db utton1) for the. SetOnClickListener {/ / using Toast Toast. MakeText (this,"You clicked Button 1",
                Toast.LENGTH_SHORT).show()
        }
    }
}
Copy the code

2.5 Use Menu in The Activity

Since the phone screen is not as big as the computer screen, Android provides a menu function to save screen space. Here’s how to use it.

2.5.1 Create the Menu folder in the RES directory

  • Create a folder of type Menu and create a Menu resource file named main

  • Modify the main code

    <? xml version="1.0" encoding="utf-8"? > <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:id="@+id/add_item"
            android:title="Add" />
        <item
            android:id="@+id/remove_item"
            android:title="Remove" />
    </menu>
    Copy the code

    Add two menu options here, where the ID attribute is the unique identifier for this option and the title is the text information displayed.

  • Override methods in FirstActivity

    Override fun onCreateOptionsMenu(menu: menu?) : Boolean {// Load the menu resource file menuinflater.inflate (R.mu.main, menu)return true} /** * Override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.add_item -> Toast.makeText(this,"You clicked Add",
                    Toast.LENGTH_SHORT).show()
            R.id.remove_item ->
                Toast.makeText(this, "You clicked Remove",
                    Toast.LENGTH_SHORT).show()
        }
        return true
    }
    Copy the code

    In the onCreateOptionsMenu method, you need to load the menu resource file and specify which menu item to add to the menu. Finally, you need to return true. If false, the menu cannot be displayed. So you need to override the onOptionsItemSelected method, and then check by itemId and make a hint.

2.6 Destroying an Activity

To destroy the Activity, simply call Finish () in the corresponding method.

button1.setOnClickListener {
    finish()
}
Copy the code

Clicking the button triggers a listening event that calls back to the Finish () method to complete the Activity’s destruction.

3. Use Intent to shuttle between activities

Intents are an important way for components to interact with each other in Android. They can not only name the action that the current component wants to perform, but they can also pass data between different components. Intents can be used to start an Activity, start a Service, and send a broadcast. Intents fall into two categories: explicit and implicit.

3.1 Using Display IntEnts

3.1.1 Create SecondActivity and modify the layout file

<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".SecondActivity">

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button 2" />
</LinearLayout>
Copy the code

3.1.2 modify FirstActivity

button1.setOnClickListener {
    val intent = Intent(this, SecondActivity::class.java)
    startActivity(intent)
}
Copy the code

An Intent object is created in the click event. The first parameter indicates the current context, and the second parameter specifies the page to jump to. SecondActivity here: : class SecondActivity in Java and Java. A class action.

3.2 Using implicit IntEnts

An implicit Intent is much more subtle than a display Intent. It does not specify which Activity to start. Instead, it specifies the action and category information for the system to analyze the Intent and find the appropriate Activity to start.

  • Modify the configuration information for SecondActivity
<activity android:name=".SecondActivity">
    <intent-filter>
        <action android:name="com.example.activitytest.ACTION_START" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
Copy the code
  • Modify the content of the Intent
button1.setOnClickListener {
    val intent = Intent("com.example.activitytest.ACTION_START")
    startActivity(intent)
}
Copy the code

To start an Activity with an implicit Intent, you must match the

and

Settings. Here you specify the contents of the < Action > tag in the SecondActivity in the configuration file. Since the

value is default, So I don’t need to specify it here.


Note: An Intent can specify only one

but can specify multiple

.

3.2.1 Specify multiple categories

button1.setOnClickListener {
    val intent = Intent("com.example.activitytest.ACTION_START")
    intent.addCategory("com.example.activitytest.MY_CATEGORY")
    startActivity(intent)
}
Copy the code

Note: When specifying multiple categories, do not forget to add the

tag to the configuration file, otherwise an error will be reported.

3.2.2 More Uses of implicit IntEnts

Implicit intEnts can be used not only to start your own Activity, but also the activities of other applications, making it possible for multiple applications to share.

  • Use Intnet to open Baidu

    button1.setOnClickListener {
        val intent = Intent(Intent.ACTION_VIEW)
        intent.data = Uri.parse("http://www.baidu.com")
        startActivity(intent)
    }
    Copy the code

    Here, specify action as ACTION_VIEW, and resolve the URI to jump to, set in the data property, you can achieve the effect of clicking the button to jump to the URL interface.

    Only when the<data>The current Activity responds to an Intent only if the content specified in the tag matches exactly the Data carried in the Intent, however<data>Tags generally do not specify too much content.

  • Open the dial page with Intent

    button1.setOnClickListener {
        val intent = Intent(Intent.ACTION_DIAL)
        intent.data = Uri.parse("tel:10086")
        startActivity(intent)
    }
    Copy the code

    Set action to DIAL and set the number.

3.2.3 Pass data to the next Activity

  • Modify the FirstActivity code

    button1.setOnClickListener {
        val data = "Hello SecondActivity"
        val intent = Intent(this, SecondActivity::class.java)
        intent.putExtra("extra_data", data)
        startActivity(intent)
    }
    Copy the code

    Here the putExtra method is used to pass the data as a key-value pair.

  • Modify the SecondActivity code

    val extraData = intent.getStringExtra("extra_data")
    Log.d("SecondActivity"."extra data is $extraData")
    Copy the code

3.2.4 Returning data to the previous Activity

  • Modify FirstActivity
    button1.setOnClickListener {
        val intent = Intent(this, SecondActivity::class.java)
        startActivityForResult(intent, 1)
    }
    Copy the code
  • Modify SecondActivity
    button2.setOnClickListener { 
        val intent = Intent()
        intent.putExtra("data_return"."Hello FirstActivity")
        setResult(RESULT_OK, intent)
        finish()
    }
    Copy the code

    This is where you need to besetResultThe status code andintentObject and destroys the Activity

  • Override methods in FirstActivity
    /** * The onActivityResult of the previous Activity is called back when the Activity started with startActivityForResult is destroyed onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) when (requestCode) { 1 ->if(resultCode == Activity.RESULT_OK) { val returnedData = data? .getStringExtra("data_return")
                Log.d("FirstActivity"."returned data is $returnedData")}}}Copy the code

    Because it might be called in an ActivitystartActivityForResultMethod to start many different activities, and the data returned by each Activity is called back toonActivityResultMethods, so need to be used to pass the checkrequestCodeDetermines the data source.

Note: The user must click the button to return the data, but clicking the back key does not return the data. To change this, you need to override another method in SecondActivity.

  • Override methods handle the back key problem

    /** * Override fun */ override fun */ override funonBackPressed() {
        val intent = Intent()
        intent.putExtra("data_return"."Hello FirstActivity")
        setResult(Activity.RESULT_OK, intent)
        finish()
    }
    Copy the code

4.Activity lifecycle

4.1 return stack

Android uses tasks to manage activities, and a task is a collection of activities stored on a stack, also known as the back stack. The stack is a lifO data structure, and by default, every time we start a new Activity, it is pushed in the back stack and at the top of the stack. Each time we press the Back key or call the Finish () method, the Activity at the top of the stack is removed, and the previous Activity is placed at the top of the stack again. The following figure shows how the Back stack manages Activity loading and unloading.

4.2 the Activity state

  • Running state

    When an Activity is at the top of the stack, it is running, and the last thing a system wants to recycle is a running Activity because it creates a poor user experience.

  • hold

    When an Activity is no longer at the top of the stack but still visible, it enters the paused state. For example, if a dialog box is displayed on top of an Activity that does not completely block the Activity, the system is reluctant to reclaim the Activity, but will consider doing so if memory is low.

  • Stop state

    An Activity enters the stopped state when it is no longer at the top of the stack and is completely invisible. The system still stores state and member variables for the Activity, but this is not entirely reliable, and stopped activities can be reclaimed by the system when memory is needed elsewhere.

  • Destruction of state

    An Activity becomes destroyed when it is removed from the return stack. The system is most likely to recycle activities in this state to ensure that the phone has enough memory.

4.3 Activity lifetime

The Activity class defines seven callback methods that cover every part of the Activity life cycle. Here’s a look at them.

  • onCreate()

    This method is called when the Activity is created for the first time. It typically performs activities related to Activity initialization, such as loading the layout, binding events, and so on.

  • onStart()

    This method is called when the Activity changes from invisible to visible.

  • onResume()

    This method is called when the Activity is ready to interact with the user, at which point the Activity must be at the top of the stack and running.

  • onPause()

    This method is called when the system is ready to start or resume another Activity. We usually use this method to free up cpu-consuming resources and save critical data, but this method must be executed fast or it will affect the use of new top-stack activities.

  • onStop()

    This method is called when the Activity is completely invisible. The main difference between onPause() and onPause() is that if the new Activity is a dialog Activity, onPause() is executed, while onStop() is not.

  • onDestroy()

    This method is called before the Activity is destroyed, after which the Activity’s state changes to destroyed.

  • onRestart()

    This method is called before the Activity changes from a stopped state to a running state, i.e. the Activity is restarted.

Note that all of the above methods, with the exception of onRestart(), are opposed to each other, so you can divide activities into the following three lifetimes.

  • Full survival:

    An Activity has a full lifetime between onCreate() and onDestroy(). Typically, an Activity completes various initialization operations in onCreate(), Free memory is done in the onDestroy() method.

  • Visible survival:

    The Activity experiences a visible lifetime between the onStart() and onStop() methods. In the visible life, activities are always visible to the user, even if they may not be able to interact with the user, we can use these two methods to manage resources that are visible to the user. For example, loading resources in the onStart() method and releasing resources in the onStop() method ensures that stopped activities do not take up too much memory.

  • Reception life:

    The foreground life an Activity experiences between onResume() and onPause() is the foreground life, during which the Activity is always running and can interact with the user. The most common Activity we encounter is in this state.

Schematic diagram of the Activity lifecycle:

4.4 Experience the Activity life cycle

4.4.1 Create two Activities and modify the layout file to include some identifiers

4.4.2 Modifying a Configuration File

Set the DialogActivity theme to Dialog style.

4.4.3 Modifying the Layout of MainActivity

<? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/startNormalActivity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start NormalActivity" />
    
    <Button
        android:id="@+id/startDialogActivity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start DialogActivity" />

</LinearLayout>
Copy the code

4.4.4 Modify the MainActivity code

class MainActivity : AppCompatActivity() {

    private val tag = "MainActivity"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(tag, "onCreate")
        setContentView(R.layout.activity_main)
        startNormalActivity.setOnClickListener{
            val intent = Intent(this, NormalActivity::class.java)
            startActivity(intent)
        }
        startDialogActivity.setOnClickListener{
            val intent = Intent(this, DialogActivity::class.java)
            startActivity(intent)
        }
    }

    override fun onStart() {
        super.onStart()
        Log.d(tag, "onStart")
    }

    override fun onResume() {
        super.onResume()
        Log.d(tag, "onResume")
    }

    override fun onPause() {
        super.onPause()
        Log.d(tag, "onPause")
    }

    override fun onStop() {
        super.onStop()
        Log.d(tag, "onStop")
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d(tag, "onDestroy")
    }

    override fun onRestart() {
        super.onRestart()
        Log.d(tag, "onRestart")}}Copy the code

After the program starts:

Click on the Dialog button

4.5 What if the Activity is Reclaimed

When we do something in ActivityA and need to jump to ActivityB, ActivityA goes into a stop state, can be reclaimed if memory is low, and when the user returns from ActivityB, ActivityA is recreated. In this way, the data saved before will be lost, which is obviously unreasonable.

Android provides an onSaveInstanceState() method, which is called before ActivityA is reclaimed, so you can save data using this method. The saved data is stored in the Bundle and can be retrieved from the Bundle object.

4.5.1 Using Bundle Objects

  • Overriding methods
    */ Override fun onSaveInstanceState(outState: override fun onSaveInstanceState) Bundle) { super.onSaveInstanceState(outState) Log.d(tag,"onCreate")
        val tempData = "Something you Just typed"
        outState.putString("data_key", tempData)
    }
    Copy the code
  • Modify the onCreate method
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(tag, "onCreate")
        setContentView(R.layout.activity_main)
        if(savedInstanceState ! = null) { val tempData = savedInstanceState.getString("data_key")
            Log.d(tag, tempData)
        }
    }
    Copy the code

    Here inBundleGet the data stored in it without being empty and print it.

5. The startup mode of the Activity

There are four startup modes for an Activity: Standard, singleTop, singleTask, singleInstance, which startup mode to use depends on the specific needs of the project. You can set the specific launchMode in the androidmanifest.xml configuration file by specifying the android:launchMode attribute to the

tag.

5.1 standard

Standard mode is the default startup mode for an Activity. All activities automatically start in this mode unless explicitly specified. In Standard mode, every time a new Activity is started, it is pushed in the back stack. For activities that use standard mode, the system does not care if the Activity already exists in the return stack. A new instance of the Activity is created each time it is started.

5.1.1 Demonstrating the Standard Mode

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.first_layout)
    button1.setOnClickListener {
        val intent = Intent(this, FirstActivity::class.java)
        startActivity(intent)
    }
}
Copy the code

A new Activity is launched each time the button is clicked here.

5.2 singleTop

In standard mode above, the Activity to be started is recreated regardless of whether the Activity is at the top of the stack. This may be unreasonable, but using singleTop mode will check whether the Activity is at the top of the stack and will not be recreated if it is.

5.2.1 Modifying a Configuration File

5.2.2 Modify the code for FirstActivity and SecondActivity

button1.setOnClickListener {
    val intent = Intent(this, SecondActivity::class.java)
    startActivity(intent)
}

button2.setOnClickListener {
    val intent = Intent(this, FirstActivity::class.java)
    startActivity(intent)
}
Copy the code

Here you only need to modify the page you want to jump to in the click event.

5.3 singleTask

The singleTop pattern used previously determines whether the Activity to be started is at the top of the stack. If not, it will be created, but this can cause multiple creation problems. However, using singleTask mode can solve this problem. It will determine whether an instance of an Activity is returned to the stack, and if so, it will be used directly and all Activity instances on that Activity will be removed from the stack.

5.3.1 Changing the Boot Mode

5.3.1 Overriding methods in FirstActivity

override fun onRestart() {
    super.onRestart()
    Log.d("FirstActivity"."onRestart")}Copy the code

5.3.2 Overriding methods in SecondActivity

override fun onDestroy() {
    super.onDestroy()
    Log.d("SecondActivity"."onDestroy")}Copy the code

5.4 singleInstance

The singleInstance startup mode differs from other startup modes in that it starts a new return stack to manage the Activity (if the singleTask mode specifies a different taskAffinity, a new return stack is also started). This startup mode is designed to solve the problem of sharing Activity instances.

5.4.1 Changing the Boot Mode

5.4.2 Printing taskId in the Activity

  • FirstActivity
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.first_layout)
        Log.d("FirstActivity"."Task id is $taskId")
        button1.setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            startActivity(intent)
        }
    }
    Copy the code
  • SecondActivity
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("SecondActivity"."Task id is $taskId")
        setContentView(R.layout.activity_second)
        button2.setOnClickListener {
            val intent = Intent(this, ThirdActivity::class.java)
            startActivity(intent)
        }
    }
    Copy the code
  • ThirdActivity
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("ThirdActivity"."Task id si $taskId")
        setContentView(R.layout.activity_third)
    }
    Copy the code

Clicking the Back key returns you directly to FirstActivity, pressing back returns you to SecondActivity, and returning again will exit the application. This happens because FirstActivity and ThirdActivity are on the same return stack, and when that return stack is empty another Activity is displayed that returns to the top of the stack.

6. Kotlin class

6.1 Standard functions with, run, apply

Kotlin’s Standard functions refer to those defined in the standard.kt file, and any Kotlin code is free to call all of the Standard functions.

6.1.1 with function

The with function takes two arguments. The first argument can be an object of any type and the second argument is a Lambda expression. The with function provides the context of the first argument object in the Lambda expression and returns the last line of code in the Lambda expression as the return value

Val result = with(obj) {// here is the context of obj"value"// return value of the with function}Copy the code

It makes code more streamlined when multiple methods on the same object are called consecutively

Need: We have a list of fruits, now we want to eat all of them and print out the results

  • The traditional writing
    val list = listOf<String>("Apple"."Banana"."Orange"."Pear"."Grape")
    val builder = StringBuilder()
    builder.append("Start eating fruit. \n")
    for (fruit in list) {
        builder.append(fruit).append("\n")
    }
    builder.append("Ate all fruits")
    
    val result = builder.toString()
    println(result)
    Copy the code
  • Use the with function
    val list = listOf<String>("Apple"."Banana"."Orange"."Pear"."Grape")
    val result = with(StringBuilder()) {
        append("Start eating fruit. \n")
        for (fruit in list) {
            append(fruit).append("\n")
        }
        append("Ate all fruits.")
        toString()
    }
    println(result)
    Copy the code

    This is passed in at the location of the contextStirngBuilderObject, then the context of the entire Lambda expression isStringBuilder, is not needed in Lambda expressionsbuilder.append()orbuilder.toString()I just need to abbreviateappend()toString()Will do, and the last line of Lambda will act aswithThe return value of the function.

6.1.2 run function

The run function is used in much the same way as the with function, with a few syntax changes. First, the run function cannot be called directly. It must call the run function of an object. Second, the run function only takes a Lambda argument and provides the context for calling the object in the Lambda expression. Everything else is the same as the with function, including using the last line of the Lambda expression as the return value.

Val result = obj.run {// where obj is the context"value"// Return value of the run function}Copy the code

Requirement: use the run function to implement the code to eat fruit

val list = listOf<String>("Apple"."Banana"."Orange"."Pear"."Grape")
val result = StringBuilder().run {
    append("Start eating fruit. \n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits.")
    toString()
}
println(result)
Copy the code

The overall change is very small, and all you need to do is call the run function with an object with just Lambda.

Also 6.1.3 the apply function

The Apply and run functions are also very similar in that they are called on an object and take only a Lambda argument. They also provide the context of the calling object in the Lambda expression, but apply cannot specify a return value. Instead, it automatically returns the calling object itself.

val list = listOf<String>("Apple"."Banana"."Orange"."Pear"."Grape")
val result = StringBuilder().apply {
    append("Start eating fruit. \n")
    for (fruit in list) {
        append(fruit).append("\n")
    }
    append("Ate all fruits.")
}
println(result.toString())
Copy the code

The difference here is that the return value needs to be called in the output statement itself, and everything else is similar.

6.2 Defining static methods

Static methods, also called class methods in some programming languages, refer to methods that can be called without creating an instance, and are supported in all major programming languages.

Defining a static method in Java is as simple as adding the static keyword to the method

public class Util {
    public static void doAction() {
        System.out.println("do action"); }}Copy the code

This is a simple utility class whose methods need only be called with util.doAction (), so static methods are great for writing utility classes because they are generally not necessary to create instances and are basically universal.

To do this in Kotlin, you need to use a singleton class, such as the Util utility class written in Kotlin above

object Util {
    fun doAction() {
        println("do action")}}Copy the code

Although the doAction() method here is not static, it can still be called using util.doaction (), which is the convenience of the singleton class.

However, writing this will make all the methods in the singleton class behave like static method calls, and you can use the Companion Object if you want only one method to behave like a static method call

class Util {
    fun doAction1() {
        println("do action1")
    }

    companion object {
        fun doAction2() {
            println("do action2")}}}Copy the code

Here the prime minister has changed the singleton class to a normal class where the doAction1() method must be called by instantiating the Util class. The doAction2() method defined in the Companion Object can be called directly from util.doaction2 ().

However, the doAction2() method is not actually a static method. The Companion object keyword actually creates a companion class inside the Util class in which the doAction2() method is defined as an instance method. It’s just that Kotlin guarantees that there will always be only one associated object in the Util class, so calling uti.doaction2 () actually calls the doAction2() method of the associated object in the Util class.

As you can see, Kotlin does not directly define keywords for static methods, but does provide syntactic features to support writing similar to static method calls. If you really need to define a true two-point static method, you can do it in Kotlin with annotations and top-level methods.

  • Annotation way

    class Util {
        fun doAction1() {
            println("do action1")
        }
    
        companion object {
            @JvmStatic
            fun doAction2() {
                println("do action2")}}}Copy the code

    Adding the @jVMStatic annotation allows the Kotlin compiler to compile this method as a true static method.

    Note: @jVMStatic annotations can only be added to methods in singleton classes and Companion Objects.

  • The top method

    Top-level methods are those that are not defined in any class, such as the main() method. Kotlin compiles all top-level methods as static methods, so whenever you define a top-level method, it must be static.

    fun doSomething() {
        println("do something")}Copy the code

    This method is defined in a new.kt file, so this method is a top-level method.

    If you want to call a top-level method in Kotlin, you just type the function name.

    If you wanted to call this method in a Java file, you wouldn’t be able to do that, because Java methods have to be written in a class.

    But Kotlin’s compiler generates a Java file from the name of the Kotlin file called Kotlin file name + kt.java, so it can be called as follows.