Lesson 3. Android Jetpack Achitecture Components

This lesson gives a brief explanation of Android Jetpack's Architecture Components.

Activity Type Lesson
Expected Duration Infinite time
Topic Main architecture components to develop a MVVM lifecycle-aware Android application
Objective Get to know Android Jetpack's architecture components

Architecture Components

The Jetpack architecture components are libraries that help design robust, testable and maintainable mobiles applications. In what remains of this lesson, some of these libraries will be explained.

Data Binding Library

As the name says it, this library helps developers to bind data from UI Components to data sources in application using a declarative format instead of a programatically approach.

Enabling Data Binding

The first thing to do is to add the dataBinding element to the build.gradle file in the app module of the application.

android{
  ...
  dataBinding{
    enabled true
  }
}

Layout Data Binding Format Declaration

As it can be seen below in the XML Layout example, the {+ \ +} tag is where data binding variables are declared. In detail, there must be a {+ \ +} tag, with a type (ex: String or a custom Object) and a unique name, for each variable intended to use.

<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="variableExample" 
      type="com.example.android.databinding.basicsample.data.SimpleViewModel"/>
  </data>

  <OtherLayoutOrUIComponent>
    <TextView android:id="@+id/myActivity_id_example"
      android:text="@{variableExample.attribute}" .../>
    ...
  </OtherLayoutOrUIComponent>
</layout>

Important

In order to convert the layout to Data Binding, you need to wrap the root element in a tag. You'll also have to move the namespace definitions (the attributes that start with xmlns:) to the new root element.

Handily, Android Studio offers a way to do this automatically.

>

Inflation of Data Binding Layouts

Due to the use of Data Binding in the Layout, there are some changes that are needed to make in the Activity/Fragment components. In detail, it is necessary to create a variable (binding object) in order to set values in the elements declared in the {+ +} tag block. The examples below show some of the ways in which inflation is done.

// Activity Inflation
val bindingVariableExample : MyActivityBinding = DataBindingUtil.setContentView(this, R.layout.name_of_Layout_file)
// Fragment Inflation
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
  ...
  bindingVariableExample = DataBindingUtil.inflate<MyActivityBinding>(inflater, R.layout.name_of_Layout_file, container, false)
  ...
}

Important

The DataBinding library generates Binding classes based on the Layout, so it'll have all the variables that were declared within it. In the example above, the class MyActivityBinding would be that auto-generated class.

Basic Knowledge, Check! Now What?

Here are some links to learn more about the things that can be done with the DataBinding Library:

LiveData Library

Is an observable data holder class that also is lifecycle-aware, so it respects the lifecycle of other app components (Activities, Fragments, etc). LiveData objects are usually used with ViewModels (i.e are used with the Android MVVM architecture). Additionally, it considers an observer to manage data-updates notifications.

Some of the advantages of using LiveData in the development of mobile applications is that it ensures NO memory leaks, NO manual lifecycle handling, up-to-date data, and that UI matches the data state, amongst other.

Adding Lifecycle and LiveData components

The first thing to do is to add the dependencies to the build.gradle file in the app module of the application.

dependencies{
  ...

  def lifecycle_version = "2.0.0"

  // ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"

  // alternatively - just LiveData
    implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"

  // Annotation Processor
  annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // use kapt for Kotlin

  // alternately - if using Java8, use the following instead of lifecycle-compiler
  implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

  ...
}

Creating LiveData Objects

As it was said before, LiveData is a wrapper that can hold any type of data (Lists, Collections, Objects, etc). Usually, it is stored within a ViewModel.

var liveDataExample: MutableLiveData<MutableList<SomeObject>> = MutableLiveData()

Update LiveData Objects

LiveData objects don't have available functions to update stored data, so the only way to update information is by using MutableLiveData. MutableLiveData extends LiveData, and the main difference between both is that MutableLiveData objects are mutable, which so it can edit the data that is holding with functions such as setValue() and postValue().

Important

The setValue() function can only be called in the Main Thread. On the other hand, the postValue() function can set values from a background thread. Nevertheless, if there are no assigned observers and the postValue() function is called, the getValue() method will not receive the update!

Observe LiveData Objects

When using LiveData objects, it is necessary to use an observer in order to see and manage updates of the data that's being handled. The example below shows how to create and assign an Observer to a LiveData object.

// Creates the observer that handles the data of the LiveData object
val observerExample = Observer<T> { data ->
  if(data != null){
      //Do Something with the Data!
  }
  ...
}

// Assigns the Observer to the LiveData object
functionThatReturnsLiveData().observe(this, observerExample)

Yey! You're still here! Want Learn More?

Here are some links to learn more about the things that can be done with the LiveData Library:

ViewModel

Is a lifecycle-aware class designed to store and manage UI-related data in a conscious way. It is responsible for preparing and managing the data for an Activity or a Fragment, and handling the communication of those components with the rest of the aplication (ex. Room Persistance Library).

Important

Every ViewModel instance will always be created/associated with either a Fragment or an Activity and will be retained as long as that scope is alive, which means that ViewModels_ have the advantage to survive configuration changes (like rotations, and stuff)!

ViewModel Diagram

Image taken from https://i1.wp.com/blog.mallow-tech.com/wp-content/uploads/2018/07/view-model.png?fit=803%2C230

Some of the advantages of using ViewModel is its capacity to survive the data related to a View Component, its aid to manage efficiently asynchronous calls, and to reduce the responsabilities of the UI Controllers.

Adding Lifecycle components

The first thing to do is to add the dependencies to the build.gradle file in the app module of the application.

dependencies{
  ...

  def lifecycle_version = "2.0.0"

  // ViewModel and LiveData
    implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"

  // alternatively - just ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version" // For Kotlin use lifecycle-viewmodel-ktx

  // Annotation Processor
  annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // use kapt for Kotlin

  // alternately - if using Java8, use the following instead of lifecycle-compiler
  implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

  ...
}

Creating and Connecting ViewModels

As it was said before, a ViewModel is a class designed to store and manage UI-related data. Usually, it stores LiveData elements to allow a fluid communication with the other components of the app. In the code bellow, there is a brief example of how to create a ViewModels class.

// Class that extends ViewModel Components
class MyFirstViewModel: ViewModel() {

  //Example of LiveData attribute
  private lateinit var liveDataList: LiveData<MutableList<CustomObject>>

  ...
}

After creating the ViewModel class, it is necessary to create the association between it and the View Component (Activity or Fragment).

// For Activity Component: 
//  Creates an instance of the MyFirstViewModel class
override fun onCreate(savedInstanceState: Bundle?) {
  ...
  //Uses the ViewModelProviders.of method to create it. 
  mViewModel = ViewModelProviders.of(this).get(MyFirstViewModel::class.java)
}
// For Fragment Component: 
//  Creates an instance of the MyFirstViewModel class
override fun onActivityCreated(savedInstanceState: Bundle?) {
  super.onActivityCreated(savedInstanceState)
  mViewModel = ViewModelProviders.of(this).get(MyFirstViewModel::class.java)
  viewModel = ViewModelProviders.of(this).get(MVVMViewModel::class.java)
}

Yes! Keep going! Keep Learning!

Here are some links to learn more about the things that can be done with the ViewModel:


Version Edited with Love by Date
1.0 Santiago Cortés Fernández February 1, 2019

results matching ""

    No results matching ""