Anko Commons Tutorial

See how to improve the readability and conciseness of your Android Kotlin code for Intents, Dialogs and more using the Anko library from JetBrains. By Arturo Mejia.

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

Alerts

Alerts in Anko Commons are a quick solution to show Alert Dialogs:

alerts

In AnimeDetailActivity, find the function showAlert and update it with the Anko version.

private fun showAlert(messageResource: Int, onYesTapped: () -> Unit, onNoTapped: () -> Unit) {
  alert(messageResource) {
    //1. Creating the alert
    yesButton {
      //2. Handling yes button (This is optional)
      onYesTapped()
    }
    noButton {
      //3. Handling no button (This is optional)
      onNoTapped()
    }
  }.show() //4. Showing the alert
}

alert is a pretty handy function, with which you can specify the title and the message of the alert with String objects or String resources.

Also, within the alert function you can specify handlers for yesButton and noButton. And if you want to have full control over the alert, it has an init function. Here are some examples:

   
alert("message").show()
alert("message", "title").show() //The title is optional
alert(R.string.message, R.string.title).show()

alert("message") {
  yesButton { } //Adds the default android.R.string.yes text to the button
  noButton { } //Adds the default android.R.string.no text to the button
}.show()

alert { //the init function where you can configure the alert as you please
  title = "title"
  message = "message"
            
  //Changing the default title
  positiveButton("Yes") {
    //Do something
  }
  //Changing the default title
  negativeButton("No") {
    //Do something
  }
}.show()

Selectors

A selector is a special type of Dialog that allows you to show a list of items.

When you tap either the thumbs up or thumbs down buttons, it shows a Dialog with a list of options in it.

In AnimeDetailActivity, search for the function showSelector() and update it with a shorter one (Anko :] ).

private fun showSelector(
    title: CharSequence, items: List<CharSequence>, onClick: (DialogInterface, Int) -> Unit) {
  selector(title,items,onClick)
}

Here is the code without Anko:

private fun showSelector(
    title: CharSequence, items: List<CharSequence>, onClick: (DialogInterface, Int) -> Unit) {
  val context = this
  
  //1. Creating the AlertDialog
  val alertBuilder = AlertDialog.Builder(context)
  
  //2. Setting the title
  alertBuilder.setTitle(title)
  
  //3. Setting click handlers for each item of the list
  alertBuilder.setItems(Array(items.size) { itemIndex -> items[itemIndex].toString() }) { dialog, which ->
    onClick(dialog, which)
  }.show()
}

As you can see, the Anko version is again much more condensed, reducing the noise in your code, and it also conveys the intention of the code just by simply reading it, instead of trying to infer the meaning of all the non-Anko lines needed to build the selector.

Progress dialogs

A ProgressDialog allows you to indicate to your users that you’re doing something that is going to take a bit to process.

share anime

In MainActivity, find the function showLoadingDialog() and update it to an Anko version:

private fun showLoadingDialog(message: String, title: String): ProgressDialog {
  val dialog = indeterminateProgressDialog(message, title) {
    //Do any customization to the dialog here
     show()
  }
  return dialog
}

Compare this with the non-Anko version:

private fun showLoadingDialog(message: String, title: String): ProgressDialog {
  val dialog = ProgressDialog(this)
  dialog.setMessage(message)
  dialog.setTitle(title)
  dialog.show()
  return dialog
}

You can create different types of progress dialogs switching between progressDialog and indeterminateProgressDialog.

Also, within the progressDialog you can specify the drawable to display the progress value, for example:

  
progressDialog("message","title").show() //The title is optional

progressDialog("message") {
  //configure the alert as you please
  val drawable = getDrawable(R.drawable.spinner)
  setTitle("title")
  // Set the drawable to be used to display the progress value.
  setProgressDrawable(drawable)
  show()
}

indeterminateProgressDialog("message","title").show()

AnkoLogger

Anko improves significantly on the Android Log class. One of the Anko advantages is that you don’t have to include a TAG name on each call to the logger, since by default it takes the name of the class as a tag.

Another positive aspect of Anko logging is that the name of the functions are nicer and more straightforward. The table below compares the Anko logger and the Android logger:

Let’s see some examples in Kanime.

In order to start using Anko Logger, first you must implement AnkoLogger in your class. In this case, have MainActivity implement AnkoLogger:

class MainActivity : AppCompatActivity(), OnAnimeClickListener, AnkoLogger {

In MainActivity, search for the functions logError() and logWTF() and update them with the Anko versions.

private fun logError() {
  error("Log Error") //Will log E/MainActivity: Log Error
}

private fun logWTF() {
  // What a Terrible Failure
  wtf("Log WTF" ) //  //Will log E/MainActivity: Log WTF
}

If you run into any trouble, make sure the imports for Anko are setup correctly:

import org.jetbrains.anko.AnkoLogger
import org.jetbrains.anko.startActivity
import org.jetbrains.anko.error
import org.jetbrains.anko.wtf

Here are the non-Anko versions for comparison:

private fun logError() {
  val tag = "MainActivity"
  val message = "Log Error"
 	
  if (Log.isLoggable(tag, Log.ERROR))
    Log.e(tag, message) //Will log I/MainActivity: Log Error
 }

private fun logWTF() {
  val tag = "MainActivity"
    
  // What a Terrible Failure
  Log.wtf(tag, message) //Will log I/MainActivity: Log WTF 
}

You’ve again reduced the boilerplate quite a bit.

An alternative to implement AnkoLogger is to have a reference to the AnkoLogger class for example:

   
val logger = AnkoLogger<YourActivity>()
logger.error("This is an error")  //Will Print E/YourActivity: This is an error

Also, you can change the tag name like this:

  
val logger = AnkoLogger("YourTag")
logger.error("This is an error") //Will Print E/YourTag: This is an error

In the same file MainActivity.kt, search for the functions
logInfo(),logVerbose(),logDebug() and logWarn(), and update them with the Anko versions.

private fun logInfo() {
  info("Log Info") //Will log I/MainActivity: Log Info

  info {
    "Log Info" //Will log I/MainActivity: Log Info
  }
}

private fun logVerbose() {
  verbose("Log Verbose") //Will log I/MainActivity: Log Verbose

  verbose {
    "Log Verbose" //Will log I/MainActivity: Log Verbose
  }
}

private fun logDebug() {
  debug("Log Debug") //Will log D/MainActivity: Log Debug

  debug {
    "Log Debug" //Will log D/MainActivity: Log Debug
  }
}

private fun logWarn() {
  warn("Log Warn") //Will log W/MainActivity: Log Warn

  warn {
    "Log Warn" //Will log W/MainActivity: Log Warn
  }
}

You see here that each of the logging functions in AnkoLogger have an alternative version that takes a Kotlin lambda as a parameter.

One important detail about AnkoLogger is that every call to the logger is checking if Log.isLoggable(yourTag, Log.SELECTED_LOG_LEVEL) is true. If not it won’t log the statement. Also, in the lambda versions, the lambda result will not be calculated if the particular log level is false.

Go ahead and build and run the final project with all the concise Anko code. You’ll see the app works just like before, but your app code is much more readablee! :]