MVVM and DataBinding: Android Design Patterns
This article describes the MVVM Design Pattern and its components, data binding, and other design patterns and architectural concepts for the Android platform. By Matei Suica.
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
MVVM and DataBinding: Android Design Patterns
30 mins
- Getting Started
- Understanding Design Patterns
- Using Architectural Design Patterns
- Common Architectural Design Patterns in Android
- MVC and MVP
- Taking the Next Step: MVVM
- Understanding MVVM Components
- Defining the Role of the View
- Defining the Model
- Finding the ViewModel’s Place in MVVM
- Improving Testability
- Hiding Behind Interfaces and Dependency Injection
- Testing Each Component
- Best practices in Testing MVVM
- Adding Android’s Architecture Components
- Using DataBinding
- Adding Android’s own ViewModel
- Loose Coupling with LiveData
- The Database in the Room
- Searching For More
- Clean Architecture
Testing Each Component
Now take a moment to review how you test each of the components covered so far.
- View: This is the simplest component in MVVM. It doesn’t know about any other component and it doesn’t control anything. Testing the View is also simple. First, provide some controlled data just like a ViewModel would. Then, check the visual results. Voilà!
- Model: This is usually simple to test also. The Model has no knowledge about the external world so you have complete control over it. All you have to do is to call “execute” methods on a Model object and then check the results with query method calls.
- ViewModel: Testing this component is a little tricky. You have to mock the Model and call methods on the ViewModel. After that, check that the data available for the View is correct. You can also check that the methods called on the mock Model are correct. If the ViewModel depends on other components, you need to mock those as well. Still, testing the ViewModel is easier than testing the components of any of the previously mentioned design patterns.
Best practices in Testing MVVM
Testing is straightforward when you apply a good pattern. There are a few secrets to testing MVVM, but here’s the best approach:
- Start testing the ViewModel. Test each one of the public methods, going through as many cases as you can. Not just the obvious paths, but real edge cases that you’re sure are never going to happen. Trust me: users and future developers will reach those edge cases. :]
- If something isn’t testable, wrap it! Create an interface that contains all of the methods you need from the untestable class. Create a class that implements that interface and instantiate the untestable class you wanted to use inside of it. Then, inside your class, call the methods from the untestable class. This is called the Proxy design pattern.
Now you have an interface you can use in your app that’s easily replaceable with a mock object. This way, you can “throw” untestable dependencies outside your class.
You should keep Android SDK framework components and external libraries at arms-length. By wrapping them this way, you make sure you don’t spread dependencies all over the code. You use the interface you’ve created and keep the frameworks and libraries in a single place.
Keep your tests short and make sure they are repeatable.
It’s not your responsibility to test the framework. You can’t control the framework, so there’s no point in testing it. If your Model only forwards methods to another library like Room, there’s not much to do in terms of testing. You can add tests once your Model needs to do something else, like filtering or computing.
Test your View with different device configurations. Mock the ViewModel to generate all the states that a View could receive.
Adding Android’s Architecture Components
So far, you’ve seen the main MVVM components and discussed testing them. But what about the Binder layer? The Android SDK provides Data Binding to implement a Binder.
Using DataBinding
Data binding is a technique that connects data sources with consumers and keeps them in sync. Android’s Data Binding Library lets the developer keep the UI in the layout XML files and generates code from them. The library also does the heavy lifting of synchronizing the View with data that comes from the ViewModel.
To add data binding to your project, you need to add the following to your app’s build.gradle file:
android {
...
dataBinding {
enabled = true
}
}
Now, your layout XMLs will need to have the following structure:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="user"
type="com.example.User" />
</data>
<ConstraintLayout... /> <!-- UI layout's root element -->
</layout>
To transform XML from the default structure to a data binding one, you need to wrap the root layout, in this case a ConstraintLayout
, inside a layout
tag. Then, at the top of the layout, just inside the layout
tag, you will need to add a data
tag, containing the objects that are used for binding.
Note: Once you have data binding enabled and sync your project, Android Studio offers a shortcut for transforming any layout into a data binding one. Select the root element of your layout and press option + return. A pop-up appears with the option “Convert to data binding layout”. Select that and the layout will add the data
and layout
tags automatically.
Note: Once you have data binding enabled and sync your project, Android Studio offers a shortcut for transforming any layout into a data binding one. Select the root element of your layout and press option + return. A pop-up appears with the option “Convert to data binding layout”. Select that and the layout will add the data
and layout
tags automatically.
The UI will reflect every change in the ViewModel via the variables inside the data
tag. In the example, there is a variable named user
.
You have to tell the UI elements what property they need. For example:
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:id="@+id/firstName"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"
android:id="@+id/lastName"/>
</LinearLayout>
</layout>
</xml>
Here there are two text views that are bound to the user.firstName
and user.lastName
values.
You will still need to add different listeners to your UI and forward those events to the ViewModel. Lucky for you, the DataBinding library can also help with that. The library generates a binding object for accessing the UI elements:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding: MyLayoutBinding = MyLayoutBinding.inflate(layoutInflater)
}
In the above, you create a binding
value using the generated binding object.
Adding Android’s own ViewModel
Creating your own ViewModel class is great, but Android Jetpack offers more. Jetpack’s ViewModel has its own lifecycle, managed by the library. This means that the library will keep the ViewModel when the OS recreates the Activity. You also don’t need to synchronize the UI state.
To begin, create a class that inherits from Jetpack’s ViewModel:
class ProfileViewModel : ViewModel() {
val uiModel: MutableLiveData<UiModel> by lazy {
MutableLiveData< UiModel >()
}
}
Then, in your Activity or Fragment, add this:
val model = ViewModelProviders.of(this).get(ProfileViewModel::class.java)
If the activity is re-created, it receives the same ProfileViewModel instance as before. When the owner activity finishes, the framework calls the ViewModel object’s onCleared()
method. That’s when the ViewModel is really destroyed.