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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Alerts
Alerts in Anko Commons are a quick solution to show Alert Dialogs:
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.
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! :]