Introduction to Kotlin Lambdas: Getting Started

In this tutorial you will learn how to use lambda expressions and other functional literals provided by Kotlin for the Android platform. Lambda expression is simplified representation of a function. It can be passed as a parameter, stored in a variable or even returned as a value. By Rachit .

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 3 of this article. Click here to view the first page.

Saving Data With Validation

Once again, in AddSongFragment.kt file, add the following lines in the saveSong() method before the return statement:

if (title.isNullOrEmpty()) {
  showError(R.string.error_title_empty)
  return false
}

if (!isValidArtist(artist)) {
  return false
}

if (!isValidYear(year)) {
  showError(R.string.error_year_invalid)
  return false
}

The code above returns false whenever any of the input fields has an invalid value. You dismiss the Add Song dialog when the saveSong() function returns true — i.e., there is no error in the input values.

Run the app. Click the Add Song button to add a new song. You will notice an error message if you provide an incorrect year or when you keep the artist name field empty.

Next, you will add a function to save the input song data to preferences.

Higher-Order Functions

A higher-order function is a function that takes functions as parameters and can also return a function. When you invoke a higher-order function you can pass lambdas or anonymous functions as parameters.

Open the SongStore.kt file and add the following function below getStoredSongs() function to save the song details:

// 1
fun saveSong(song: String, onSuccess: (() -> Unit)?, onError: (Int) -> Unit) {
  // 2  
  val songs = getStoredSongs()
  if (songs.contains(song)) {
    // 3
    onError(R.string.error_song_exists)
  } else {
    // 4
    songs.add(song)
    preferences.edit(true) {
    putStringSet(STORE_KEY, songs)
  }
  onSuccess?.invoke()
  }
}

Remember to import the required dependencies with Opt + Enter (or Alt + Enter on Windows).

In the code above code, you:

  1. Define a high-order function name saveSong(). It takes the first parameter song of type String, the second parameter is named onSuccess with a function type, and the third parameter onError is also a function type.
  2. Check for duplication by getting all songs and checking if the new song already exists.
  3. In case of duplication, show an error by calling onError() function.
  4. Successfully save the song to store and call the onSuccess() function.

You still need call the above function from the saveSong() in AddSongFragment class after you have validated the input data.

Go back to AddSongFragment.kt file and add the following code to the saveSong() method before the last return statement:

  songStore.saveSong("$title, $artist, $year", onSongAdded::onSongAdded, this::showError)

In the above code, you call the saveSong function from the SongStore class and pass the input data after validation. Its fourth parameter is a function reference to OnSongAdded interface function. Its fifth parameter is a function reference to the showError function defined in AddSongFragment.

Build and run. Finally, now when you save a song, it is stored in the Preferences. The Add Song dialog will be dismissed, and the newly added song will be shown on the home screen.

Next, you will add a function to find the year range of your song playlist by using Closures.

Understanding Closures

A closure is a lambda that is able to read and modify the variables defined outside its scope. It is also known as variable capture inside lambda. It minimizes code redundancy and improves the overall readability.

Go back to MainActivity.kt and add the following code below the showAllSongs() function:

// 1
private fun findPlaylistYearRange(songs: List<String>) {
  // 2
  if (songs.isEmpty()) {
    return
  }
  // 3
  var startYear = songs[0].split(",")[2].trim().toInt()
  var endYear = startYear
  // 4
  val findStartEndYear = {
    songs.forEach { song ->
      val songYear = song.split(",")[2].trim().toInt()
      if (songYear > endYear) {
        endYear = songYear
      } else if (songYear < startYear) {
        startYear = songYear
      }
    }
  }
  // 5
  findStartEndYear()

  // 6
  text_view_total.text = "($startYear - $endYear) - Total: ${songs.count()}"
}

In the code above, you:

  1. Define a function findPlaylistYearRange(). It takes a list of String as a single parameter.
  2. If there is no any song, do not show anything.
  3. Set the value of startYear to the year of the first song in the song list. You also define the endYear equal to the startYear.
  4. Define a lambda expression to calculate the year range and store it in findStartEndYear variable. This lambda expression can access and modify the values of startYear and endYear defined outside its scope. This is referred as a Lambda closure.
  5. Call the lambda expression to find the year range.
  6. Set the year range text to text_view_year_range view.

You need to call this function to see the year range on the screen.

In the MainActivity.kt file, add the following code below to the end of showAllSongs function:

  findPlaylistYearRange(songs)

Build and deploy the app to check out the year range of your playlist.

Where to Go From Here?

Congratulation! You learned many concepts about lambda and applied those to your app. While developing Android apps, you might have used lambda expressions even without knowing what they are because Android Studio help you convert interface to lambda expression whenever possible. Now you understand how Android Studio simplifies your code.

You can use the Download Materials button at the top or bottom of this tutorial to download the final project.

Be sure to keep yourself updated with our latest tutorials on Android and Kotlin. You may take the Android and Kotlin learning path for a more comprehensive understanding of building apps for Android.

We hope it was fun learning about lambdas. If you have questions and comments, please join the discussions in the forums.

Good luck! :]