Android ViewModel LiveData Kotlin

The ViewModel class is designed to store and manage Ui-related data in a life-cycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations .

Android Framework manages the life-cycle of activity and fragment , whenever there is configuration changes such as screen rotation or applying/toggling dark mode then the framework decides to recreate and any transient Ui-related data you store in them will be lost .

Save and Restore Data On Configuration Change


For simple data, the activity can use the onSaveInstanceState() method and restore its data from the bundle in onCreate(), but this approach is only suitable for small amounts of data that can be serialized then deserialized, not for potentially large amounts of data like a list of users or bitmaps ViewModel is best suitable save and restore large anount of data .

ViewModel LifeCycle


The above diagram illustrates the various life-cycle states of an activity as it undergoes a rotation and then is finished  and the ViewModel which is associated with the activity will exist until the activity is fully destroyed .


Gradle


file: build.gradle(app)
 
dependencies {

 implementation "android.arch.lifecycle:extensions:1.1.1"
 annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
}

LiveData 


LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the life-cycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active life-cycle state.

Activities and fragments safely observe LiveData objects and not worry about leaks activities and fragments are instantly unsubscribed to livedata when their lifecycles are destroyed.

The advantages of using LiveData
  • Ensures your UI matches your data state
  • No memory leaks
  • No crashes due to stopped activities
  • No more manual lifecycle handling
  • Always up to date data
  • Proper configuration changes
  • Sharing resources

Create LiveData objects


LiveData is a wrapper that can be used with any data, including objects that implement Collections,
such as List. A LiveData object is usually stored within a ViewModel object
Inside Your ViewModel declare and initialize viewmodel
 var myRandomNumber = MutableLiveData<String>().apply {
        value = (0..10).random().toString()
    }

Observer LiveData Changes .


Generally, LiveData delivers updates only when data changes, and only to active observers(Activities or fragments) . Inside the onCreate method of activity call observe on livedata which defined inside the viewmodel.
 mainActivityViewModel.myRandomNumber.observe(this, Observer {
            textview.text = it
        })

In this tutorial we will see a simple example , where we will generate random number inside the onCreate method and set it to textview and when the device is rotate the random value should not change , also we will have button widget and inside the onclick listener of button make changes to livedata which is defined inside viewmodel , change in livedata notifies the observe(Activity) and upadte UI with newly changed value

ViewModel


  • Create a MainActivityViewModel by extending ViewModel class .
  • Define a LiveData by wrapping to the String data variable .
  • Add createRandomNumber which modifies the livedata , when will be called on button click event  .
file : MainActivityViewModel.kt
package com.tutorialsbuzz.viewmodelsample

import android.util.Log
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import java.util.concurrent.atomic.AtomicInteger

class MainActivityViewModel : ViewModel() {

    val TAG: String = MainActivityViewModel::class.java.simpleName

    var myRandomNumber = MutableLiveData<String>().apply {
        value = (0..10).random().toString()
    }

    fun createRandomNumber() {
        Log.d(TAG, "createRandomNumber");
        myRandomNumber.value = (0..10).random().toString()
    }

    override fun onCleared() {
        super.onCleared()
        Log.d(TAG, "onCleared");
    }
}

XML Layout


Create XML Layout activity_main.xml , this will be set as content view for launcher Activity (MainActivity.kt) and add TextView and Button to your layout file

file : activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvNumber"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:gravity="center"
        android:text=""
        android:textSize="30sp" />

    <Button
        android:id="@+id/update"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:gravity="center"
        android:text="update"
        android:textSize="30sp" />

</LinearLayout>

MainActivity 

  • Create a koltin class MainActivity.kt and extend it to AppCompatActivity class .
  • Override onCreate function and set the content of this MainActivity with above defined xml layout (activity_main.xml). 
  • Setup the activity with the above define MainActivityViewModel .
  • Set the random number to TextView .
  • On Button click call createRandomNumber method of MainActivityViewModel .

file : MainActivity.kt
package com.tutorialsbuzz.viewmodelsample

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)


        val mainActivityViewModel =
            ViewModelProviders.of(this).get(MainActivityViewModel::class.java)

        mainActivityViewModel.myRandomNumber.observe(this, Observer {
            tvNumber.text = it
        })

        update.setOnClickListener({
            mainActivityViewModel.createRandomNumber()
        })

    }
}

Portrait
Landscape



Observe LiveData Changes :



No comments:

Post a Comment