In this article, I will explain how to implement MVVM pattern with Android Architecture Components. Android Architecture components contain a bunch of libraries that will help you to build android applications in the MVVM pattern. Few of them are Room, ViewModel, LiveData. Before going to example let’s understand these components one by one.

Lifecycle-Aware Components

These are the components that automatically responds according to life-cycle events. These components will help you produce better, lightweight, easier to maintain code. Take the example of LocationListener. When we create LocationListener in Activity we have to manage its connectivity. When activity launches we have started listening to location changes. Now when activity pauses we have to pause listening to location changes. But now with Lifecycle-Awareness of the component, we don’t need to handle pausing location updates. Just pass the lifecycle owner to the component and rest will be taken care of by the component itself.

ViewModel

The ViewModel is used to persist data during various configuration changes like screen rotation. Suppose we are fetching data from the server inside the activity. Now if we did not persist data inside ViewModel. The user rotates the screen then it will again fetch data which is a costly process. To avoid these unnecessary transactions to the server we can use ViewModel.

LiveData

LiveData is a data holder class. Data inside this holder can be observed for changes. So we can add data and keep track of data changes to modify UI accordingly. LiveData is lifecycle-aware that is it responds according to the state of activity or fragment. It keeps your UI up to date with the latest data. It avoids memory leaks as data get cleared as the associated lifecycle is destroyed. no crashes due to stopped activities. You can create a single point of contact for data retrieval that keeps your code robust, clean, and easier to maintain.

Room Persistence Library

Room Persistence Library provides an abstraction layer over the SQLite database. The room makes database CRUD operations easier and more maintainable. The room shows an error if you have written the wrong query while compiling your application. Room works with LiveData to keep your UI and Data in sync. Room uses entities for structuring database and dao( data access object )  to perform CRUD( Create, Read, Update, Delete) operations. we will see more about it as we go in this article.

Repository

The repository can be called a single source of truth for all application data. When we have both local and online database then it becomes hard to manage both databases. With Repository we can create a single source for any type of data source. Now data coming from a single source will make code easier to maintain.

Demo

Android Architecture Components | MVVM in Android with Room, LiveData and ViewModel | loopiki.com

Download Project

MVVM in Android with Room, LiveData and ViewModel

Below is stranded MVVM architecture in android using Room, LiveData, and ViewModel. Using this architecture we will build notes application. In this application, we will be able to add notes and display notes in recycler view.

Android Architecture Components | MVVM in Android with Room, LiveData, and ViewModel

Adding Room, LiveData, ViewModel Library to Android Studio Project

Create new or open an existing android studio project. Open build.greadle(module app). Add dependencies for Room, LiveData, ViewModel as shown below. CardView dependency is optional due to the design requirement of this example.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.loopwiki.androidarchitecturecomponants"
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    buildToolsVersion '27.0.3'
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support.constraint:constraint-layout:1.1.0'
    implementation 'com.android.support:design:27.1.1'
    // ViewModel and LiveData library depenedecies
    implementation 'android.arch.lifecycle:extensions:1.1.1'
    implementation 'com.android.support:support-v4:27.1.1'
    annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
    // Room library depenedecies
    implementation 'android.arch.persistence.room:runtime:1.0.0'
    annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
    //CardView dependency optional required in design of example
    implementation 'com.android.support:cardview-v7:27.1.1'
}

Project Structure

Create packages for activities, adapters, databases, repositories, utils, viewModels, Daos, and models. This will maintain the project in a good structure.

Android Architecture Complainants | MVVM in Android with Room, LiveData and ViewModel - Project Structure
Android Architecture Components | MVVM in Android with Room, LiveData, and ViewModel – Project Structure

Creating Entity

Create new class in Package Name --> database.-> models -> Note.java. This class will represent the note structure in the database. The note will have a unique id, title, description, and created as shown below.

package com.loopwiki.androidarchitecturecomponants.database.models;

import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey;
import android.arch.persistence.room.TypeConverters;

import com.loopwiki.androidarchitecturecomponants.utils.DateConverter;

import java.util.Date;
// Entity class model of room database
@Entity
public class Note {
    // room database entity primary key
    @PrimaryKey(autoGenerate = true)
    public int id;
    private String noteTitle;
    private String noteDescription;
    //type converter for date
    @TypeConverters(DateConverter.class)
    private Date createdAt;

    public Note(String noteTitle, String noteDescription, Date createdAt) {
        this.noteTitle = noteTitle;
        this.noteDescription = noteDescription;
        this.createdAt = createdAt;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getNoteTitle() {
        return noteTitle;
    }

    public void setNoteTitle(String noteTitle) {
        this.noteTitle = noteTitle;
    }

    public String getNoteDescription() {
        return noteDescription;
    }

    public void setNoteDescription(String noteDescription) {
        this.noteDescription = noteDescription;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }
}

Now we can not store data directly we need type converter for that so create new class Package Name -> utils -> DateConverter.java. Add the following lines of code into it.

package com.loopwiki.androidarchitecturecomponants.utils;

import android.arch.persistence.room.TypeConverter;
import android.text.format.DateFormat;

import java.util.Date;

public class DateConverter {

    @TypeConverter
    public static Date toDate(Long timestamp) {
        return timestamp == null ? null : new Date(timestamp);
    }

    @TypeConverter
    public static Long toTimestamp(Date date) {
        return date == null ? null : date.getTime();
    }


    public static String getDayMonth(Date date) {

        String day = (String) DateFormat.format("dd", date); // 20
        String monthString = (String) DateFormat.format("MMM", date); // Jun
        return day + monthString;
    }
}

Creating Dao( Data Access Object)

Dao( Data Access Object) used to perform CRUD operations on the database. Create new class Package Name -> database ->  NoteDao.java. Define Methods to insert, delete, getting all notes as shown below.

package com.loopwiki.androidarchitecturecomponants.database.Daos;

import android.arch.lifecycle.LiveData;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.TypeConverters;

import com.loopwiki.androidarchitecturecomponants.utils.DateConverter;
import com.loopwiki.androidarchitecturecomponants.database.models.Note;

import java.util.List;

import static android.arch.persistence.room.OnConflictStrategy.REPLACE;

//note dao(data access object)
@Dao
@TypeConverters(DateConverter.class)
public interface NoteDao {
    // Dao method to get all notes
    @Query("SELECT * FROM Note")
    LiveData<List<Note>> getAllNotes();

    // Dao method to insert note
    @Insert(onConflict = REPLACE)
    void insertNote(Note note);

    // Dao method to delete note
    @Delete
    void deleteNote(Note note);
}

Creating Room Database

Create new abstract class extending RoomDatabase inside Package Name -> database -> NoteDatabase.java. This class used to create an instance of Room Database. Inside this class provide all entities and dao’s. The structure of this class is as shown below.

package com.loopwiki.androidarchitecturecomponants.database;

import android.arch.persistence.room.Database;
import android.arch.persistence.room.Room;
import android.arch.persistence.room.RoomDatabase;
import android.content.Context;

import com.loopwiki.androidarchitecturecomponants.database.Daos.NoteDao;
import com.loopwiki.androidarchitecturecomponants.database.models.Note;

// Room database class
@Database(entities = Note.class, version = 1, exportSchema = false)
public abstract class NoteDatabase extends RoomDatabase {
    //define static instance
    private static NoteDatabase mInstance;

    //method to get room database
    public static NoteDatabase getDatabase(Context context) {

        if (mInstance == null)
            mInstance = Room.databaseBuilder(context.getApplicationContext(),
                    NoteDatabase.class, "notes_db")
                    .build();

        return mInstance;
    }

    //method to remove instance
    public static void closeDatabase() {
        mInstance = null;
    }

    //define note dao ( data access object )
    public abstract NoteDao noteDao();


}

Creating Repository

Create new class Package Name -> repositories -> NotesRepository.java. This class will serve as a true source of data. Create methods to get data from Room database or any other database like firebase. Inside create LiveData of List of all notes and methods to add a note inside Room Database as shown below.

package com.loopwiki.androidarchitecturecomponants.repositories;

import android.app.Application;
import android.arch.lifecycle.LiveData;
import android.os.AsyncTask;
import android.support.annotation.NonNull;

import com.loopwiki.androidarchitecturecomponants.database.Daos.NoteDao;
import com.loopwiki.androidarchitecturecomponants.database.NoteDatabase;
import com.loopwiki.androidarchitecturecomponants.database.models.Note;

import java.util.List;
//Notes repository 
public class NotesRepository {
    //Live Data of List of all notes
    private LiveData<List<Note>> mAllNotes;
    //Define Notes Dao
    NoteDao mNoteDao;

    public NotesRepository(@NonNull Application application) {
        NoteDatabase noteDatabase = NoteDatabase.getDatabase(application);
        //init Notes Dao
        mNoteDao = noteDatabase.noteDao();
        //get all notes
        mAllNotes = mNoteDao.getAllNotes();
    }
    //method to get all notes
    public LiveData<List<Note>> getAllNotes() {
        return mAllNotes;
    }

    //method to add note
    public void addNote(Note note) {
        new AddNote().execute(note);
    }

    //Async task to add note
    public class AddNote extends AsyncTask<Note, Void, Void> {
        @Override
        protected Void doInBackground(Note... notes) {
            mNoteDao.insertNote(notes[0]);
            return null;
        }
    }
}

We will display all notes inside recycler view. Before creating activity we will create an adapter and required layouts for recyclerview.

Creating Adapter for Recyclerview

Create new file in res -> layout -> custom_row_note.xml. This row will represent the view of a single note in recyclerview as shown below.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/backStrip"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="8dp"
            android:layout_marginStart="8dp"
            android:background="@android:color/white">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentStart="true"
                android:layout_marginBottom="8dp"
                android:layout_marginLeft="4dp"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/noteTitle"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:textAppearance="@style/TextAppearance.AppCompat.Medium"
                    android:textStyle="bold" />

                <TextView
                    android:id="@+id/noteDescription"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:textAppearance="@style/TextAppearance.AppCompat.Medium" />

                <TextView
                    android:id="@+id/createdAt"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:lines="1"
                    android:textAppearance="@style/TextAppearance.AppCompat.Medium"
                    android:textColor="@color/colorPrimary" />

            </LinearLayout>


        </RelativeLayout>
    </FrameLayout>

</android.support.v7.widget.CardView>

Create new class inside Package Name -> adapters -> NotesAdapter.java. This class will serve as an adapter for recyclerview. Create viewholder and bind data to the view inside onCreateViewHolder() and onBindViewHolder() methods respectively as shown below.

package com.loopwiki.androidarchitecturecomponants.adapters;

import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.loopwiki.androidarchitecturecomponants.utils.DateConverter;
import com.loopwiki.androidarchitecturecomponants.R;
import com.loopwiki.androidarchitecturecomponants.database.models.Note;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class NotesAdapter extends RecyclerView.Adapter {
    //Create list of notes
    List<Note> notes = new ArrayList<>();

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //Get layout inflater
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        //Inflate layout
        View row = inflater.inflate(R.layout.custom_row_note, parent, false);
        //return notes holder and pass row inside
        return new NoteHolder(row);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        //Get current note
        Note currentNote = notes.get(position);
        //cast notes holder
        NoteHolder noteHolder = (NoteHolder) holder;
        //set title description and created at
        noteHolder.mNoteTitle.setText(currentNote.getNoteTitle());
        noteHolder.mNoteDescription.setText(currentNote.getNoteDescription());
        noteHolder.createdAt.setText(DateConverter.getDayMonth(currentNote.getCreatedAt()));
        //create random color and set it
        Random rnd = new Random();
        int color = Color.argb(255, rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
        noteHolder.backStrip.setBackgroundColor(color);
    }

    @Override
    public int getItemCount() {
        return notes.size();
    }

    public class NoteHolder extends RecyclerView.ViewHolder {
        TextView mNoteTitle, mNoteDescription, createdAt;
        FrameLayout backStrip;

        public NoteHolder(View itemView) {
            super(itemView);
            mNoteTitle = itemView.findViewById(R.id.noteTitle);
            mNoteDescription = itemView.findViewById(R.id.noteDescription);
            createdAt = itemView.findViewById(R.id.createdAt);
            backStrip = itemView.findViewById(R.id.backStrip);
        }
    }

    public void addNotes(List<Note> notes) {
        this.notes = notes;
        notifyDataSetChanged();
    }
}

Create new class inside Package Name -> utils -> Space.java. This class is recyclerview decoration class used to add space between recyclerview items. Add the following lines to it

package com.loopwiki.androidarchitecturecomponants.utils;

import android.content.Context;
import android.graphics.Rect;
import android.support.annotation.DimenRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class Space extends RecyclerView.ItemDecoration {
    private int mItemOffset;

    public Space(int itemOffset) {
        mItemOffset = itemOffset;
    }

    public Space(@NonNull Context context, @DimenRes int itemOffsetId) {
        this(context.getResources().getDimensionPixelSize(itemOffsetId));
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                               RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (parent.getChildLayoutPosition(view) == 0)
            outRect.top = mItemOffset;
        outRect.left = mItemOffset;
        outRect.right = mItemOffset;
        outRect.bottom = mItemOffset;
    }
}

Creating ViewModel

It’s time to create viewmodel for notes. Create class inside Package name -> viewModels -> NotesListViewModel.java. This ViewModel will contain LiveData of all notes and methods to insert notes as defined below.

package com.loopwiki.androidarchitecturecomponants.viewModels;

import android.app.Application;
import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData;
import android.support.annotation.NonNull;

import com.loopwiki.androidarchitecturecomponants.repositories.NotesRepository;
import com.loopwiki.androidarchitecturecomponants.database.models.Note;

import java.util.List;

public class NotesListViewModel extends AndroidViewModel {
    private LiveData<List<Note>> mAllNotes;
    NotesRepository mNotesRepository;

    public NotesListViewModel(@NonNull Application application) {
        super(application);
        mNotesRepository = new NotesRepository(application);
        mAllNotes = mNotesRepository.getAllNotes();
    }

    public LiveData<List<Note>> getAllNotes() {
        return mAllNotes;
    }

    public void addNote(Note note) {
        mNotesRepository.addNote(note);
    }
}

Creating Activity

Finally create new layout res -> layout -> content_main.xml. Inside this layout define recyclerview as given below.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:id="@+id/content_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".activities.MainActivity"
    tools:showIn="@layout/activity_main">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerViewNotes"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</android.support.constraint.ConstraintLayout>

Create one more layout res -> layout -> activity_main.xml. This layout will contain contain_main.xml, app bar, floating action button inside coordinator layout as below.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
    tools:context=".activities.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            app:layout_scrollFlags="snap|enterAlways|scroll"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:src="@drawable/ic_add_black_24dp"
        android:tint="@android:color/white"
        android:layout_margin="16dp" />

</android.support.design.widget.CoordinatorLayout>

Create custom layout for add note dialogue res -> layout -> add_note_dialog.xml. Add the following code to it.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="Add Note"
        android:textAppearance="@style/TextAppearance.AppCompat.Large.Inverse" />

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:hint="Title">

        <android.support.design.widget.TextInputEditText
            android:id="@+id/editTextTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </android.support.design.widget.TextInputLayout>

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        android:hint="Description">

        <android.support.design.widget.TextInputEditText
            android:id="@+id/editTextDescription"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </android.support.design.widget.TextInputLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="end|right"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/textViewAdd"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:text="Add"
            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
            android:textColor="@color/colorPrimary" />

        <TextView
            android:id="@+id/textViewCancel"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="16dp"
            android:text="Cancel"
            android:textAppearance="@style/TextAppearance.AppCompat.Medium"
            android:textColor="@color/colorPrimary" />

    </LinearLayout>

</LinearLayout>

Create new class Package Name -> activities -> MainActivity.java. Bind recyclerview and other views inside activity. Then get ViewModel for the activity using ViewModelProviders as shown below. showDialog() method used to show add notes dialogue.

package com.loopwiki.androidarchitecturecomponants.activities;

import android.app.Dialog;
import android.arch.lifecycle.Observer;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.EditText;
import android.widget.TextView;

import com.loopwiki.androidarchitecturecomponants.R;
import com.loopwiki.androidarchitecturecomponants.adapters.NotesAdapter;
import com.loopwiki.androidarchitecturecomponants.database.models.Note;
import com.loopwiki.androidarchitecturecomponants.utils.Space;
import com.loopwiki.androidarchitecturecomponants.viewModels.NotesListViewModel;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    NotesListViewModel mNotesListViewModel;
    FloatingActionButton fab;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        // Initialize floating action button
        fab = (FloatingActionButton) findViewById(R.id.fab);
        //show add notes dialogue
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showDialog();
            }
        });
        // bind recyclerview to object
        RecyclerView mNotesRecyclerView = findViewById(R.id.recyclerViewNotes);
        // set layout manager
        mNotesRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        // create new notes adapter
        final NotesAdapter notesAdapter = new NotesAdapter();
        // set adapter to recyclerview
        mNotesRecyclerView.setAdapter(notesAdapter);
        // add decoration to recyclerview
        mNotesRecyclerView.addItemDecoration(new Space(20));
        // get ViewModel of this activity using ViewModelProviders
        mNotesListViewModel = ViewModelProviders.of(this).get(NotesListViewModel.class);
        // observe for notes data changes
        mNotesListViewModel.getAllNotes().observe(this, new Observer<List<Note>>() {
            @Override
            public void onChanged(@Nullable List<Note> notes) {
                //add notes to adapter
                notesAdapter.addNotes(notes);
            }
        });

    }

    public void showDialog() {
        fab.hide();
        final Dialog dialog = new Dialog(this);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialog.setContentView(R.layout.add_note_dialog);
        dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        final EditText editTextTitle = dialog.findViewById(R.id.editTextTitle);
        final EditText editTextDescription = dialog.findViewById(R.id.editTextDescription);
        TextView textViewAdd = dialog.findViewById(R.id.textViewAdd);
        TextView textViewCancel = dialog.findViewById(R.id.textViewCancel);
        textViewAdd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String Title = editTextTitle.getText().toString();
                String Description = editTextDescription.getText().toString();
                Date createdAt = Calendar.getInstance().getTime();
                //add note
                mNotesListViewModel.addNote(new Note(Title, Description, createdAt));
                fab.show();
                dialog.dismiss();
            }
        });
        textViewCancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
                fab.show();
            }
        });

        dialog.show();

    }

}

Modify colors.xml, styles.xml, manifest.xml as below.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#ffc107</color>
    <color name="colorPrimaryDark">#ffa000</color>
    <color name="colorAccent">#6200ea</color>
</resources>
<resources>
    <string name="app_name">Android Architecture Componants</string>
</resources>
<resources>

    <! – Base application theme. – >
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <! – Customize your theme here. – >
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="AppTheme.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

</resources>

Run application

Android Architecture Components | MVVM in Android with Room, LiveData and ViewModel - Output
Android Architecture Components | MVVM in Android with Room, LiveData, and ViewModel – Output

If you still have any queries, please post them in the comments section below, I will be happy to help you.

Author

Hello there, My name is Amardeep founder of loopwiki.com. I have experience in many technologies like Android, Java, Php, etc. In this variety of technologies, I love Android App Development. If you have any idea and you want me to develop for you then let's have chat Conatct

3 Comments

  1. Hi nice elaborate tutorial. How can I represent the created date as days ago? 4 days ago

Write A Comment