<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=160269078105920&amp;ev=PageView&amp;noscript=1">
This service has been removed!
Service successfully added!
Sign up for our blog, talk to a specialist, or just send us an email

MVVM + Data Binding + Kotlin = Efficient and Easier Code

Tuesday 22 of May, 2018./ Reading Time: 14 minutes./ By Marcos Sandoval

Blog

As a software developer, we are always looking for ways to improve how we write and organize code. The main goal of this is to make sure our code is easy to maintain. We also want to be able to have the same functionality with less, or at least the same, amount of code in the future. Kotlin and Android Data binding work together to build an MVVM architecture that achieves the above goals.

Before we start with the code, we are going to do a quick review of the three most common architectures used in Android: MVC, MVP and MVVM. Next, we’ll identify why we are focusing this article on MVVM.

MVC

 

imagen1

In all three architectures, the user interacts with the View Layer. However, in the case of MVC, this interaction is transferred from the View to the Controller, which should be able to understand and process the user request and interact with the Model to update it if necessary. Then, the Model can fire events to update to View based on the latest changes. There is an interaction between the Model and the View, which is normally implemented using an observable pattern or manually, through the Controller.

MVP
imagen2

 

Using MVP, we have a loosely coupled architecture since the Presenter receives the user inputs via the View, processes them with the help of the model, and updates the View. There is no communication between the Model and the View. There is a one-to-one relationship between the View and the Presenter, with each view having a reference to the Presenter through an interface for user requests processing. Also, the Presenter communicates with the View for UI updates using another interface which gets rid of the coupled code. This makes the Unit testing, maintenance, and future improvements easier to do.

MVVM
imagen3

 

MVVM is very similar to MVP in terms of how the code is organized, but with the big difference that it includes the term “Bidirectional Data Binding”. On MVVM, the View has a state which basically represents the current status of the information displayed to the user. This information has to correspond with the current state of the objects at the View Model layer. In order to keep this information synchronized, we use Bidirectional Data Binding, which is an implementation of Observable Pattern that keeps us posted about the changes in the layers and allows us to react to these changes by updating the View or changing the Model. We are talking about Reactive Programming to handle the communication between two layers, without writing tons of code.

Time for the code

We are going to create a very simple app using MVVM, Android Data binding, Kotlin and even a Reactive Programming component (Observer and Observable). The example is an application that allows us to create a nutritional plan and lets us know how many calories we are eating. Let’s get started!

Gradle File

To be able to use Data binding, we need to update our app level gradle file. We need to add the Data binding dependency and enable it. The file should looks like this:

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'

android {
  ...
  dataBinding {
      enabled = true
  }
  ...
}

dependencies {
  …

  ///the compiler version must be the same than our gradle version
  kapt 'com.android.databinding:compiler:3.1.1'
}

 

Models

The sample app will be composed of 2 Data Clases

● Food

● Nutritional Plan

 Food

This data class has 2 attributes. Thanks to Kotlin, we just need one line of code to declare these two attributes, its getters and setters methods, its visibility and the class constructor.

data class Food (val name: String, val calories: Int)

 

Nutritional Plan

It has two attributes, a list of Food objects and an integer that represents the total calories on the plan. It also has a function that we will use after to add a new Food to the Nutritional Plan.

data class NutritionalPlan (var foods: MutableList<Food> = mutableListOf(), val totalCalories: ObservableInt = ObservableInt()){

   fun addFood(food: Food){
       foods.add(food)
       totalCalories.set(totalCalories.get() + food.calories)
   }
}

 

One thing to notice here:

totalCalories field is an ObservableInt property, which is an Observable object that has only one property, an int. This way, when totalCalories is modified, it will automatically notify to all the subscribers of Nutritional Plan about the change. Otherwise we had to use notifyObservers method to manually notify about the change

View Model

In the case of our Nutritional Plan app we have only one View Model, let’s go straight to the code.

class NutritionalPlanViewModel(var nutritionalPlan : NutritionalPlan = NutritionalPlan()) : Observable() {

   fun addFood(name: String, calories: Int){
       val food = Food(name, calories)
       nutritionalPlan.addFood(food)
       setChanged()
       notifyObservers()
   }

   fun showAddFoodDialog(){
       setChanged()
       notifyObservers(SHOW_ADD_FOOD_DIALOG)
   }

   companion object {
       const val SHOW_ADD_FOOD_DIALOG = "show add food dialog"
   }
}

 

Some things to know about this code:

● It has just one property, which is an instance of Nutritional Plan class we created before

● It extends from Observable class, which allows us, by the use of Observable pattern, create a Reactive app. In this case, our View Model class will notify all its observer when something change on it. This is done by the use of setChanged method(which basically marks that the observable has been changed) and notifyObservers() method (which notifies all the observers of the change, it takes an Object as a parameter, in our case we’re sending an event of show a dialog to the user)

● As we noticed there isn’t references to any View, which means one View Model can be tied to more than one View and they communicate each other using Data Binding and Observable events.

View

Let’s begin with the XML code. Our layout file is called MainActivity.xml.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto"
   xmlns:tools="http://schemas.android.com/tools">

   <data>
       <variable
           name="viewModel"
       type="com.androidtraining.MVVMDatabindingKotlin.viewModel.NutritionalPlanViewModel"/>
   </data>


   <android.support.constraint.ConstraintLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       tools:context=".view.MainActivity">
       ...
       <TextView
           android:id="@+id/tv_total_calories"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_marginEnd="8dp"
           android:layout_marginStart="8dp"
           android:layout_marginTop="5dp"
           android:text="@{String.valueOf(viewModel.nutritionalPlan.totalCalories)}"
           android:textSize="13sp"
           app:layout_constraintEnd_toEndOf="parent"
           app:layout_constraintStart_toStartOf="parent"
           app:layout_constraintTop_toBottomOf="@+id/tv_title" />

       ...

       <android.support.design.widget.FloatingActionButton
           android:id="@+id/btn_add_food"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:layout_gravity="bottom|end"
           android:layout_marginBottom="10dp"
           android:layout_marginEnd="10dp"
           android:elevation="10dp"
           android:onClick="@{() -> viewModel.showAddFoodDialog()}"
           android:src="@android:drawable/ic_input_add"
           app:fabSize="normal"
           app:layout_constraintBottom_toBottomOf="parent"
           app:layout_constraintEnd_toEndOf="parent" />

   </android.support.constraint.ConstraintLayout>
</layout>

 

Some things to be noticed on the layout file:

● We omitted a Textview and a RecyclerView, since they are not relevant for this example

● On the Data tag we declare a variable called viewModel, which is an instance of View Model class described above

● The TextView with the id tv_total_calories gets the text to display from the View Model, using the viewModel variable mentioned above

● The onClick event handler also uses the viewModel variable to call a method to execute the corresponde actions

Come on with the MainActivity class, which is an Observer that’s subscribed to the View Model Observable to react to any notifications emitted by it.

class MainActivity : AppCompatActivity(), Observer {
   private val viewModel = NutritionalPlanViewModel()

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       initbinding()
   }

   override fun update(p0: Observable?, p1: Any?) {
       if(p1.toString() == NutritionalPlanViewModel.SHOW_ADD_FOOD_DIALOG){
           showDialog(viewModel)
       }
   }

   private fun initbinding(){
       val activityMainBinding =  DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)

       activityMainBinding.viewModel = viewModel
       viewModel.addObserver(this)
       rv_foods.layoutManager = LinearLayoutManager(this)
       var adapter = RecyclerAdapter(viewModel.nutritionalPlan.foods, this)
       rv_foods.adapter = adapter
       btn_add_food.setOnClickListener({showDialog(viewModel)})

   }

   private fun showDialog(viewModel: NutritionalPlanViewModel){
       var dialog = AddFoodDialog.newInstance(viewModel)
       dialog.show(supportFragmentManager, "")
   }
}

 

Things to know about the code:

addObserver is called to subscribe our Observer(the View) to the Observable (the View Model)

● We use DataBindingUtil.setContentView method instead of the regular setContentView, because the first one returns an instance of ActivityMainBinding which is an auto-generated class base on the layout file. This class holds all the bindings from the layout properties. In our case we only have one property called viewModel; it also knows how to assign the values to the binding expressions

activityMainBinding.viewModel set the View Model of the viewModel variable declared on the layout

Update function receives all the events triggered by the Observable, p0 represents the object that emitted the signal indicating it was modified and p1 is an object sent as extra information. It could be any kind of object

Conclusion

And that’s it! Using a very little amount of code we have an MVVM architecture that automatically updates the view base on the changes on the View Model and also keeps the View synchronized with the Model through the View Model layer.

About Avantica

If you are looking for a software partner who will work towards your own business goals and success, then Avantica is your solution. We offer dedicated teams, team augmentation, and individual projects to our clients, and are constantly looking for the best methodologies in order to give you the best results.

 

Let’s start a project together

Join our newsletter

PREVIOUS
Accessibility Testing: Make Sure Your Software Is Used By All
NEXT
Event-Based Computing (AWS Lambda) and the Serverless Future