There are a lot of great places where you can get started with Android. In this post we assume you did a tutorial and go from there. We will talk about Recyclerview, ViewModels, Data Binding and more.

The place where I started out with Android development is here on Udacity. For the hard core documentation readers the android documentation is found here.

To help understand with what we will talk about I made an example app. The code can be found here on github so you can run it yourself and play around with it.

Garden Planner

The example app is called Garden Planner and will help you with your own garden by reminding you on maintenance or suggesting new additions. In the first version we just want some example data for these actions in a list that we can scroll through. Running it on an emulator will look something like this.

Screenshot 2019 10 17 at 09.03.27 - ANDROID RECYCLERVIEW

Layouts

Layouts are the visual components of your app. In the res/layout directory you find 3 files. The activity_main.xml is the android starting point but we will be more concerned with the other two files.

The list_item_action.xml is the design for a single action item. It uses a constraint layout where boundaries are relative to other elements or to the parent. This works pretty intuitive when you play around in the design tab of the fragment. Note that the margins are really important for look and feel of the item.

Screenshot 2019 10 21 at 10.46.01 - ANDROID RECYCLERVIEW

The fragment_home.xml is the top level layout and also has a constraint layout. It simply has the title at the top and then the list of actions. This list is done with a Recyclerview, which is an android specific optimised list that reuses the items that scroll off the screen.

Populate Recyclerview

To fill our list with data we need to define a domain model and a repository that provides this data. This is not the focus of this post and we will use mock data in the repository. Note that the actions have type LiveData<> which is an Android type that updates automatically when the source changes.

The HomeViewModel controls the data for the HomeFragment. It only holds the reference to the Action list LiveData.

class HomeViewModel(application: Application, actionRepository: ActionRepository) : AndroidViewModel(application) {

    val actionList: LiveData<List<Action>> = actionRepository.actionList
}

Recyclerview needs a ListAdapter which is an abstraction on top of the items in the Recyclerview list. To implement this ListAdapter we need to override methods that define what to do on creation of the list and how to bind an item. The essence of this we can find in the inner class of the ActionAdapter.

class ViewHolder private constructor(val binding: ListItemActionBinding): RecyclerView.ViewHolder(binding.root) {
    
    companion object {
        fun from(parent: ViewGroup): ViewHolder {
            val layoutInflater = LayoutInflater.from(parent.context)
            val binding = ListItemActionBinding.inflate(layoutInflater, parent, false)

            return ViewHolder(binding)
        }
    }

    fun bind(item: Action) {
        binding.action = item
        binding.executePendingBindings()
    }
}

We use the from method on creation to inflate the view the binding. In the bind method we bind the specific action to the list item.

In the HomeFragment we set the adapter on the Recyclerview and bind the data from de ViewModel to the Recyclerview.

val adapter = ActionAdapter()
binding.actionList.adapter = adapter
homeViewModel.actionList.observe(viewLifecycleOwner, Observer {
    it?.let {
        adapter.submitList(it)
    }
})

Data Binding

Until now we have a ViewModel with the data and an Adapter for the Recyclerview items. Android has a way to bind directly from the adapter to layout with data binding.

In the layout we reference an action variable.

<data>
    <variable
        name="action"
        type="nl.sybrenbolandit.gardenplanner.domain.Action" />
</data>

In the TextView we use the @{} notation to point to the defined action.

<TextView
    android:id="@+id/actionTitle"
    ...
    app:actionTitle="@{action}" />

We defined the bindingAdapter actionTitle in a separate file /fragment/home/ActionBinginAdapters. Here we use kotlins extension functions to extend the TextView with our actionTitle method.

@BindingAdapter("actionTitle")
fun TextView.setActionTitle(item: Action?) {
    item?.let { text = item.title }
}

Now the TextView can show the title of the product using Data Binding.

Hopefully you can now use the power of the Android Recyclerview in your own apps. Happy recycling!