




















































In this article, we will build a simple to-do list app that allows a user to add and display tasks.
In this process, we will learn the following:
This article is taken from the book Learning Kotlin by building Android Applications by Eunice Adutwumwaa Obugyei and Natarajan Raman. This book will teach you programming in Kotlin including data types, flow control, lambdas, object-oriented, and functional programming while building Android Apps.
Let's start by creating a new project in Android Studio, with the name TodoList. Select Add No Activity on the Add an Activity to Mobile screen:
When the project creation is complete, create a Kotlin Activity by selecting File | New | Kotlin Activity, as shown in the following screenshot:
This will start a New Android Activity wizard. On the Add an Activity to Mobile screen, select Basic Activity, as shown in the following screenshot:
Now, check Launcher Activity on the Customize the Activity screen, and click the Finish button:
In Android, the code for your user interface is written in XML. You can build your UI by doing either of the following:
Let's go ahead and start designing our TodoList app.
Android Studio provides a layout editor, which gives you the ability to build your layouts by dragging widgets into the visual editor. This will auto-generate the XML code for your UI.
Open the content_main.xml file.
Make sure the Design tab at the bottom of the screen is selected, as shown in the following screenshot:
To add a component to your layout, you just drag the item from the Palette on the left side of the screen. To find a component, either scroll through the items on the Palette, or click on the Palette search icon and search for the item you need.
Go ahead and add a ListView to your view. When a view is selected, its attributes are displayed in the XML Attributes editor on the right side of the screen. The Attributes editor allows you to view and edit the attributes of the selected component. Go ahead and make the following changes:
Now, select Text at the bottom of the editor window to view the generated XML code. You'll notice that the XML code now has a ListView placed within the ConstraintLayout:
Instead of using the layout editor, you could have written the previous code yourself. The choice between using the layout editor or writing the XML code is up to you. You can use the option that you're most comfortable with. We'll continue to make additions to the UI as we go along.
Now, build and run your code. as shown in the following screenshot:
As you can see, the app currently doesn't have much to it. Let's go ahead and add a little more flesh to it.
Since we'll use the FloatingActionButton as the button the user uses to add a new item to their to-do list, we need to change its icon to one that makes its purpose quite clear.
Open the activity_main.xml file:
One of the attributes of the android.support.design.widget.FloatingActionButton is app:srcCompat. This is used to specify the icon for the FloatingActionButton. Change its value from @android:drawable/ic_dialog_email to @android:drawable/ic_input_add.
Build and run again. The FloatingActionButton at the bottom now looks like an Add icon, as shown in the following screenshot:
At the moment, when the user clicks on the Add button, a ticker shows at the bottom of the screen. This is because of the piece of code in the onCreate() method that defines and sets an OnClickListener to the FloatingActionButton:
fab.setOnClickListener { view -> Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show() }
This is not ideal for our to-do list app. Let's go ahead and create a new method in the MainActivity class that will handle the click event:
fun showNewTaskUI() { }
The method currently does nothing. We'll add code to show the appropriate UI soon. Now, replace the code within the setOnClickListener() call with a call to the new method:
fab.setOnClickListener { showNewTaskUI() }
For adding a new task, we'll show the user an AlertDialog with an editable field.
Let's start by building the UI for the dialog. Right-click the res/layout directory and select New | Layout resource file, as shown in the following screenshot:
On the New Resource File window, change the Root element to LinearLayout and set the File name as dialog_new_task. Click OK to create the layout, as shown in the following screenshot:
Open the dialog_new_task layout and add an EditText view to the LinearLayout. The XML code in the layout should now look like this:
Now, let's go ahead and add a few string resources we'll need for the next section. Open the res/values/strings.xml file and add the following lines of code to the resources tag:
<string name="add_new_task_dialog_title">Add New Task</string> <string name="save">Save</string>
The best way to use an AlertDialog is by encapsulating it in a DialogFragment. The DialogFragment takes away the burden of handling the dialog's life cycle events. It also makes it easy for you to reuse the dialog in other activities.
Create a new Kotlin class with the name NewTaskDialogFragment, and replace the class definition with the following lines of code:
class NewTaskDialogFragment: DialogFragment() { // 1 // 2 interface NewTaskDialogListener { fun onDialogPositiveClick(dialog: DialogFragment, task: String) fun onDialogNegativeClick(dialog: DialogFragment) }
var newTaskDialogListener: NewTaskDialogListener? = null // 3 // 4 companion object { fun newInstance(title: Int): NewTaskDialogFragment { val newTaskDialogFragment = NewTaskDialogFragment() val args = Bundle() args.putInt("dialog_title", title) newTaskDialogFragment.arguments = args return newTaskDialogFragment } } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { // 5 val title = arguments.getInt("dialog_title") val builder = AlertDialog.Builder(activity) builder.setTitle(title) val dialogView = activity.layoutInflater.inflate(R.layout.dialog_new_task, null) val task = dialogView.findViewById<EditText>(R.id.task) builder.setView(dialogView) .setPositiveButton(R.string.save, { dialog, id -> newTaskDialogListener?.onDialogPositiveClick(this, task.text.toString); }) .setNegativeButton(android.R.string.cancel, { dialog, id -> newTaskDialogListener?.onDialogNegativeClick(this) }) return builder.create() } override fun onAttach(activity: Activity) { // 6 super.onAttach(activity) try { newTaskDialogListener = activity as NewTaskDialogListener } catch (e: ClassCastException) { throw ClassCastException(activity.toString() + " must implement NewTaskDialogListener") } } }
Let's take a closer look at what this class does:
Now, open the MainActivity class. Change the class declaration to include implementation of the NewTaskDialogListener. Your class declaration should now look like this:
class MainActivity : AppCompatActivity(), NewTaskDialogFragment.NewTaskDialogListener {
And, add implementations of the methods declared in the NewTaskDialogListener by adding the following methods to the MainActivity class:
override fun onDialogPositiveClick(dialog: DialogFragment, task:String) { }
override fun onDialogNegativeClick(dialog: DialogFragment) { }
In the showNewTaskUI() method, add the following lines of code:
val newFragment = NewTaskDialogFragment.newInstance(R.string.add_new_task_dialog_title) newFragment.show(fragmentManager, "newtask")
In the preceding lines of code, the newInstance() method in NewTaskDialogFragment is called to generate an instance of the NewTaskDialogFragment class. The show() method of the DialogFragment is then called to display the dialog.
Build and run. Now, when you click the Add button, you should see a dialog on your screen, as shown in the following screenshot:
As you may have noticed, nothing happens when you click the SAVE button. In the onDialogPositiveClick() method, add the line of code shown here:
Snackbar.make(fab, "Task Added Successfully", Snackbar.LENGTH_LONG).setAction("Action", null).show()
As we may remember, this line of code displays a ticker at the bottom of the screen.
Now, when you click the SAVE button on the New Task dialog, a ticker shows at the bottom of the screen.
We're currently not storing the task the user enters. Let's create a collection variable to store any task the user adds. In the MainActivity class, add a new variable of type ArrayList<String>, and instantiate it with an empty ArrayList:
private var todoListItems = ArrayList<String>()
In the onDialogPositiveClick() method, place the following lines of code at the beginning of the method definition:
todoListItems.add(task) listAdapter?.notifyDataSetChanged()
This will add the task variable passed to the todoListItems data, and call notifyDataSetChanged() on the listAdapter to update the ListView.
Saving the data is great, but our ListView is still empty. Let's go ahead and rectify that.
To make changes to a UI element in the XML layout, you need to use the findViewById() method to retrieve the instance of the element in the corresponding Activity of your layout. This is usually done in the onCreate() method of the Activity.
Open MainActivity.kt, and declare a new ListView instance variable at the top of the class:
private var listView: ListView? = null
Next, instantiate the ListView variable with its corresponding element in the layout. Do this by adding the following line of code at the end of the onCreate() method:
listView = findViewById(R.id.list_view)
To display data in a ListView, you need to create an Adapter, and give it the data to display and information on how to display that data. Depending on how you want the data displayed in your ListView, you can either use one of the existing Android Adapters, or create your own. For now, we'll use one of the simplest Android Adapters, ArrayAdapter. The ArrayAdapter takes an array or list of items, a layout ID, and displays your data based on the layout passed to it.
In the MainActivity class, add a new variable, of type ArrayAdapter:
private var listAdapter: ArrayAdapter<String>? = null
Add the method shown here to the class:
private fun populateListView() { listAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, todoListItems) listView?.adapter = listAdapter }
In the preceding lines of code, we create a simple ArrayAdapter and assign it to the listView as its Adapter.
Now, add a call to the previous method in the onCreate() method:
populateListView()
Build and run. Now, when you click the Add button, you'll see your entry show up on the ListView, as shown in the following screenshot:
In this article, we built a simple TodoList app that allows a user to add new tasks, and edit or delete an already added task. In the process, we learned to use ListViews and Dialogs.
Next, to learn about the different datastore options available and how to use them to make our app more usable, read our book, Learning Kotlin by building Android Applications.
6 common challenges faced by Android App developers.
Google plans to let the AMP Project have an open governance model, soon!
Entry level phones to taste the Go edition of the Android 9.0 Pie version