A Simple Basic Example of ViewModel

 ViewModelExample  is a very straightforward app with buttons that increase Or decrease  the no of items. The finished app has a bug though; if you rotate the phone, your selected number of items will again set up with the initial value.

        

What’s going on? Rotating a device is one of a few configuration changes that an app can go through during its lifetime. When configurations changed during run time (such as screen orientation, keyboard availability, and language), Android usually destroys application’s existing Activity or Fragment and recreate it.

ViewModel

At Google I/O 2017, the Android Framework team introduced a new set of Architecture Components, one of which deals with this exact rotation issue.

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

Download Github code from here.

Previously, you might have used onRetainNonConfigurationInstance to save this data during a configuration change and unpack it on the other end.

In the diagram below, you can see the lifecycle of an Activity which undergoes a rotation and then is finally finished. The lifetime of the ViewModel is shown next to the associated Activity lifecycle. Note that ViewModels can be easily used with both Fragments and Activities, which I’ll call UI controllers. This example focuses on Activities.

The ViewModel exists when you first request a ViewModel (usually in the onCreate the Activity) until the Activity is finished and destroyed. onCreate may be called several times during the life of an Activity, such as when the app is rotated, but the ViewModel survives throughout.

There are three steps to setting up and using a ViewModel:

Step 1: Create a ViewModel class

public class OrderViewModel extends ViewModel {

    public int orderedCoffee = 0;

    public int orderedTea = 0;

    public int orderedColddrink = 0;

}

Step 2: Set up communications between your ViewModel and your UI controller

Your UI controller ( Activity or Fragment) needs to know about your ViewModel. This is so your UI controller can display the data and update the data when UI interactions occur, such as pressing a button to increase or decrease the no of items.

OrderViewModel mViewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

mViewModel = ViewModelProviders.of(this).get(OrderViewModel.class);
displayNoOfCoffee(mViewModel.orderedCoffee);
}

Step 3: Use the ViewModel in your UI Controller

To access or change UI data, you can now use the data in your ViewModel. Here’s an example of the new onCreate method and a method for updating the no of items :

OrderViewModel mViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
btnIncreaseCoffee = (Button) findViewById(R.id.btn_increase_coffee);
btnDecreaseCoffee = (Button) findViewById(R.id.btn_decrease_coffee);


noOfCoffee = (TextView) findViewById(R.id.tv_no_ofcoffee);
mViewModel = ViewModelProviders.of(this).get(OrderViewModel.class);
displayNoOfCoffee(mViewModel.orderedCoffee);
public void displayNoOfCoffee(int coffee) {

    noOfCoffee.setText(coffee + "");
}
@Override
public void onClick(View view) {

    switch (view.getId()) {
        case R.id.btn_increase_coffee: {
            mViewModel.orderedCoffee = mViewModel.orderedCoffee + 1;
            displayNoOfCoffee(mViewModel.orderedCoffee);
            break;
        }
        case R.id.btn_decrease_coffee: {
            if (mViewModel.orderedCoffee > 0) {
                mViewModel.orderedCoffee = mViewModel.orderedCoffee - 1;
                displayNoOfCoffee(mViewModel.orderedCoffee);
            }
            break;
        }
}

The first time the ViewModelProviders method is called by MainActivity, it creates a new ViewModel instance. When this method is called again, which happens whenever onCreate is called, it will return the pre-existing ViewModel associated with the specific ViewModelExample MainActivity. This is what preserves the data.

Creating New Project

1.In Android Studio, go to File New Project and fill all the details required to create a new project. When it prompts to select a default activity, select Blank Activity and proceed.

2.Open build.gradle and add ViewModel dependency.

Build.gradle

dependencies {
        
    //viewmodel dependency
    implementation "android.arch.lifecycle:extensions:1.0.0"
    annotationProcessor "android.arch.lifecycle:compiler:1.0.0"

}

3.  Open OrderViewModel.Java and write the below code.

OrderViewModel.Java

package com.example.lenovo.viewmodelexample;

import android.arch.lifecycle.ViewModel;

public class OrderViewModel extends ViewModel {

    public int orderedCoffee = 0;

    public int orderedTea = 0;

    public int orderedColddrink = 0;

}

4.  Open activity_main.xml and write the below code.Here to increase or decrease items i have created increase and decrease button.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.lenovo.viewmodelexample.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:padding="8dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginBottom="15dp"
            android:layout_marginTop="15dp"
            android:fontFamily="sans-serif"
            android:text="Order what you would like to drink?"
            android:textColor="@android:color/holo_blue_dark"
            android:textSize="22sp" />

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:fontFamily="sans-serif"
                android:text="No. of coffee"
                android:textColor="@android:color/holo_red_light"
                android:textSize="20sp" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:orientation="horizontal">

                <Button
                    android:id="@+id/btn_increase_coffee"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:text="+" />

                <TextView
                    android:id="@+id/tv_no_ofcoffee"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:padding="8dp" />

                <Button
                    android:id="@+id/btn_decrease_coffee"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:text="-" />

            </LinearLayout>

        </RelativeLayout>

        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:fontFamily="sans-serif"
                android:text="No. of tea"
                android:textColor="@android:color/holo_red_light"
                android:textSize="20sp" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:orientation="horizontal">

                <Button
                    android:id="@+id/btn_increase_tea"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:text="+" />

                <TextView
                    android:id="@+id/tv_no_oftea"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:padding="8dp" />

                <Button
                    android:id="@+id/btn_decrease_tea"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:text="-" />

            </LinearLayout>

        </RelativeLayout>


        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:fontFamily="sans-serif"
                android:text="No. of colddrink"
                android:textColor="@android:color/holo_red_light"
                android:textSize="20sp" />

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:orientation="horizontal">

                <Button
                    android:id="@+id/btn_increase_colddrink"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:text="+" />

                <TextView
                    android:id="@+id/tv_no_ofcolddrink"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:padding="8dp" />

                <Button
                    android:id="@+id/btn_decrease_colddrink"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:text="-" />

            </LinearLayout>

        </RelativeLayout>

        <Button
            android:id="@+id/btn_order"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="10dp"
            android:text="order" />
    </LinearLayout>
</ScrollView>

5.  Open MainActivity.Java and write the below code.Here I have set up connection between UI controller
and ViewModel and also perform read and write operation on viewmodel.

MainActivity.Java

package com.example.lenovo.viewmodelexample;

import android.arch.lifecycle.ViewModelProviders;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button btnIncreaseCoffee, btnDecreaseCoffee, btnIncreaseTea, btnIncreaseColddrink, btnDecreaseTea, btnDecreaseColddrink;
    Button btnOrder;
    TextView noOfCoffee, noOfTea, noOfColddrink;
    OrderViewModel mViewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnIncreaseCoffee = (Button) findViewById(R.id.btn_increase_coffee);
        btnDecreaseCoffee = (Button) findViewById(R.id.btn_decrease_coffee);

        btnIncreaseTea = (Button) findViewById(R.id.btn_increase_tea);
        btnDecreaseTea = (Button) findViewById(R.id.btn_decrease_tea);

        btnIncreaseColddrink = (Button) findViewById(R.id.btn_increase_colddrink);
        btnDecreaseColddrink = (Button) findViewById(R.id.btn_decrease_colddrink);

        btnOrder = (Button) findViewById(R.id.btn_order);

        noOfCoffee = (TextView) findViewById(R.id.tv_no_ofcoffee);
        noOfTea = (TextView) findViewById(R.id.tv_no_oftea);
        noOfColddrink = (TextView) findViewById(R.id.tv_no_ofcolddrink);

        //adding listener
        btnIncreaseCoffee.setOnClickListener(this);
        btnDecreaseCoffee.setOnClickListener(this);
        btnIncreaseTea.setOnClickListener(this);
        btnDecreaseTea.setOnClickListener(this);
        btnIncreaseColddrink.setOnClickListener(this);
        btnDecreaseColddrink.setOnClickListener(this);
        btnOrder.setOnClickListener(this);


        mViewModel = ViewModelProviders.of(this).get(OrderViewModel.class);
        displayNoOfCoffee(mViewModel.orderedCoffee);
        displayNoOfTea(mViewModel.orderedTea);
        displayNoOfColddrink(mViewModel.orderedColddrink);

    }

    public void displayNoOfCoffee(int coffee) {
        noOfCoffee.setText(coffee + "");
    }

    public void displayNoOfTea(int tea) {
        noOfTea.setText(tea + "");
    }

    public void displayNoOfColddrink(int colddrink) {
        noOfColddrink.setText(colddrink + "");
    }

    @Override
    public void onClick(View view) {

        switch (view.getId()) {
            case R.id.btn_increase_coffee: {
                mViewModel.orderedCoffee = mViewModel.orderedCoffee + 1;
                displayNoOfCoffee(mViewModel.orderedCoffee);
                break;
            }
            case R.id.btn_decrease_coffee: {
                if (mViewModel.orderedCoffee > 0) {
                    mViewModel.orderedCoffee = mViewModel.orderedCoffee - 1;
                    displayNoOfCoffee(mViewModel.orderedCoffee);
                }
                break;
            }
            case R.id.btn_increase_tea: {
                mViewModel.orderedTea = mViewModel.orderedTea + 1;
                displayNoOfTea(mViewModel.orderedTea);
                break;
            }
            case R.id.btn_decrease_tea: {
                if (mViewModel.orderedTea > 0) {
                    mViewModel.orderedTea = mViewModel.orderedTea - 1;
                    displayNoOfTea(mViewModel.orderedTea);
                }
                break;
            }
            case R.id.btn_increase_colddrink: {
                mViewModel.orderedColddrink = mViewModel.orderedColddrink + 1;
                displayNoOfColddrink(mViewModel.orderedColddrink);
                break;
            }
            case R.id.btn_decrease_colddrink: {
                if (mViewModel.orderedColddrink > 0) {
                    mViewModel.orderedColddrink = mViewModel.orderedColddrink - 1;
                    displayNoOfColddrink(mViewModel.orderedColddrink);
                }
                break;
            }
            case R.id.btn_order: {
                Toast.makeText(this, "\n" + mViewModel.orderedCoffee + " " + "Coffee" + "\n" + mViewModel.orderedTea + " " + "Tea" + "\n" +
                        mViewModel.orderedColddrink + " " + "Colddrink" + "\n", Toast.LENGTH_LONG).show();
                break;
            }

        }

    }
}

When you run the app it will look like this:

Vertical Orientation
Horizontal Orientation

 

Leave a Reply