Introduction to Android Activities with Kotlin

Learn about one of the most important concepts within Android apps with this introduction to Android activities tutorial, using Kotlin! By Steve Smith.

4.3 (22) · 1 Review

Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Starting an Activity

In its current state, the app is a fairly useless lump of ones and zeros because you can’t add anything to the to-do list. You have the power to change that, and that’s exactly what you’ll do next.

In the MainActivity.kt file you have open, add a property to the top of the class:

private val ADD_TASK_REQUEST = 1

You’ll use this immutable value to reference your request to add new tasks later on.

Then add this import statement at the top of the file:

import android.content.Intent

And add the following implementation for addTaskClicked():

val intent = Intent(this, TaskDescriptionActivity::class.java)
startActivityForResult(intent, ADD_TASK_REQUEST)

When the user taps the “ADD A TASK” button, the Android OS calls addTaskClicked(). Here you create an Intent to launch the TaskDescriptionActivity from MainActivity.

Note: There will be a compile error since you have yet to define TaskDescriptionActivity.

You can start an activity with either startActivity() or startActivityForResult(). They are similar except that startActivityForResult() will result in onActivityResult() being called once the TaskDescriptionActivity finishes. You’ll implement this callback later so you can know if there is a new task to add to your list or not.

But first, you need a way to enter new tasks in Forget Me Not — you’ll do so by creating the TaskDescriptionActivity.

Note: Intents are used to start activities and pass data between them. For more information, check out the Android: Intents Tutorial

Creating an Activity

Android Studio makes it very easy to create an activity. Just right-click on the package where you want to add the activity — in this case, the package is com.raywenderlich.android.forgetmenot. Then navigate to New\Activity, and choose Empty Activity, which is a basic template for an activity:

On the next screen, enter TaskDescriptionActivity as the Activity Name and Android Studio will automatically fill the other fields based on that.

Click Finish and put your hands in the air to celebrate. You’ve just created your first activity!

Android Studio will automatically generate the corresponding resources needed to create the activity. These are:

  • Class: The class file is named TaskDescriptionActivity.kt. This is where you implement the activity’s behavior. This class must subclass the Activity class or an existing subclass of it, such as AppCompatActivity.
  • Layout: The layout file is located under res/layout/ and named activity_task_description.xml. It defines the placement of different UI elements on the screen when the activity is created.

The layout file created from the Empty Activity template in Android Studio 3.0 and above defaults to using a ConstraintLayout for the root view group. For more information on ConstraintLayout, please see the android developer docs here.

In addition to this, you will see a new addition to your app’s AndroidManifest.xml file:

<activity android:name=".TaskDescriptionActivity"></activity>

The activity element declares the activity. Android apps have a strong sense of order, so all available activities must be declared in the manifest to ensure the app only has control of activities declared here. You don’t want your app to accidentally use the wrong activity, or even worse, have it use activities that are used by other apps without explicit permission.

There are several attributes that you can include in this element to define properties for the activity, such as a label or icon, or a theme to style the activity’s UI.

android:name is the only required attribute. It specifies the activity’s class name relative to the app package (hence the period at the beginning).

Now build and run the app. When you tap on ADD A TASK, you’re presented with your newly generated activity!

Looking good, except for the fact that it’s lacking substance. Now for a quick remedy to that!

In your newly generated TaskDescriptionActivity, paste the following into your class file, overwriting anything else except the class declaration and its brackets.

// 1
companion object {
  val EXTRA_TASK_DESCRIPTION = "task"
}

// 2
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_task_description)
}

// 3
fun doneClicked(view: View) {

}

Note: You can quickly fix any missing imports that Android Studio complains about by placing your cursor on the item and pressing option+return on Mac or Alt+Enter on PC.

Here, you’ve accomplished the following:

  1. Used the Kotlin companion object for the class to define attributes common across the class, similar to static members in Java.
  2. Overriden the onCreate() lifecycle method to set the content view for the activity from the layout file.
  3. Added an empty click handler that will be used to finish the activity.

Jump over to your associated layout in res/layout/activity_task_description.xml and replace everything with the following:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:padding="@dimen/default_padding"
  tools:context="com.raywenderlich.android.forgetmenot.TaskDescriptionActivity">

  <TextView
    android:id="@+id/descriptionLabel"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="@dimen/default_padding"
    android:text="@string/description"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

  <EditText
    android:id="@+id/descriptionText"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:inputType="textMultiLine"
    android:padding="@dimen/default_padding"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/descriptionLabel" />

  <Button
    android:id="@+id/doneButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:onClick="doneClicked"
    android:padding="@dimen/default_padding"
    android:text="@string/done"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/descriptionText" />

</android.support.constraint.ConstraintLayout>

Here you change the layout so there is a TextView prompting for a task description, an EditText for the user to input the description, and a Done button to save the new task.

Run the app again, tap ADD A TASK and your new screen will look a lot more interesting.

Stopping an Activity

Just as important as starting an activity with all the right methods is properly stopping it.

In TaskDescriptionActivity.kt, add these imports, including one for Kotlin Android Extensions:

import android.app.Activity
import android.content.Intent
import kotlinx.android.synthetic.main.activity_task_description.*

Then add the following to doneClicked(), which is called when the Done button is tapped in this activity:

// 1
val taskDescription = descriptionText.text.toString()

if (!taskDescription.isEmpty()) {
  // 2
  val result = Intent()
  result.putExtra(EXTRA_TASK_DESCRIPTION, taskDescription)
  setResult(Activity.RESULT_OK, result)
} else {
  // 3
  setResult(Activity.RESULT_CANCELED)
}

// 4
finish()

You can see a few things are happening here:

  1. You retrieve the task description from the descriptionText EditText, where Kotlin Android Extensions has again been used to get references to view fields.
  2. You create a result Intent to pass back to MainActivity if the task description retrieved in step one is not empty. Then you bundle the task description with the intent and set the activity result to RESULT_OK, indicating that the user successfully entered a task.
  3. If the user has not entered a task description, you set the activity result to RESULT_CANCELED.
  4. Here you close the activity.

Once you call finish() in step four, the callback onActivityResult() will be called in MainActivity — in turn, you need to add the task to the to-do list.

Add the following method to MainActivity.kt, right after onCreate():

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
  // 1
  if (requestCode == ADD_TASK_REQUEST) {
    // 2
    if (resultCode == Activity.RESULT_OK) {
      // 3
      val task = data?.getStringExtra(TaskDescriptionActivity.EXTRA_TASK_DESCRIPTION)
      task?.let {
        taskList.add(task)
        // 4
        adapter.notifyDataSetChanged()
      }
    }
  }
}

Let’s take this step-by-step:

  1. You check the requestCode to ensure the activity result is indeed for your add task request you started with TaskDescriptionActivity.
  2. You make sure the resultCode is RESULT_OK — the standard activity result for a successful operation.
  3. Here you extract the task description from the result intent and, after a null check with the let function, add it to your list.
  4. Finally, you call notifyDataSetChanged() on your list adapter. In turn, it notifies the ListView about changes in your data model so it can trigger a refresh of its view.

Build and run the project to see it in action. After the app starts, tap ADD A TASK. This will bring up a new screen that lets you enter a task. Now add a description and tap Done. The screen will close and the new task will be on your list: