Fire Base with Kotlin MVVM

ChandraSaiMohan bhupathi
CodeX
Published in
7 min readApr 2, 2021
Using FireBase with MVVM
FireBase with MVVM using Kotlin

This story demonstrates a sample android application for using FireBase Database with MVVM using Kotlin.

The application uses below features of firebase:

(1) Authentication

(2) Real time Database

(3) Storage

Brief introduction of Sample app:

The sample that is used as part of demonstration contains below screens:

(1) Login Screen : Authenticates the logged user with email/password provided

(2)Registration screen : This screen allows user to register with email/password over firebase.

For the above 2 screens we use firebase “Authentication” feature.

(3) Tax Info Entry screen: In this screen user will be provided UI to enter info about Tax bills and submit that data. Allows user to upload pdf docs as proof for bills.

This screen uses firebase “Realtime Database” and “storage” features.

(4)Tax List: This screen displays list of Tax details entered by user based on email ID

This screen uses firebase “Realtime Database”.

App Implementation Details:

Step 1 : Registered my app over firebase console and below screen shoot for the same:

To register my app I followed the steps as described below in firebase documentation .

Step2:

Enabled the features required for my app as below:

(a) Authentication

Authentication

Enabled Email/Password as authentication mechanism for this app. We can enable any of the Authentication mechanisms based on app requirement .

Click on users tab we can view list of registered users

(b) Realtime Database: Enabled real time database feature to save my app’s data.

I have table named “taxInfo”. The table data is represented as nodes as FireBase use NOSQL as underlying DataBase

© FireBase Cloud storage:

The pdf docs or any type of files can be saved in FireBase by enabling “storage” feature. When a file is uploaded in FireBase we receive in response URL of that file which is easy to maintain in DB.

App project structure:

Used MVVM design pattern. Handled all the interaction with FireBase in the ViewModel and providing required data to be consumed by Views

In the ViewModel initialized all the required FireBase features in the init block as below:

private var  auth: FirebaseAuth? = null
private var storage: FirebaseStorage
private var storageReference: StorageReference
private var rootNode: FirebaseDatabase
private var reference: DatabaseReference
var loading: MutableLiveData<Boolean> = MutableLiveData()
init {

auth = FirebaseAuth.getInstance() //Authentication
storage = FirebaseStorage.getInstance() //File/image uploads
storageReference = storage.reference //Reference to the storage
rootNode = FirebaseDatabase.getInstance() // Realtime DB
reference = rootNode.getReference("taxInfo") //Reference to DBTable
loading.postValue(false)

}

Authentication:

To register an user firebase provides below API :

authentication.createUserWithEmailAndPassword(email,password)
.addOnCompleteListener {task: Task<AuthResult> ->
if(!task.isSuccessful){
println("Registration Failed with ${task.exception}")
_registrationStatus.postValue(ResultOf.Success("Registration Failed with ${task.exception}"))
}else{
_registrationStatus.postValue(ResultOf.Success("UserCreated"))

}
loading.postValue(false)
}

Authenticate User:

auth?.let{ login->
login.signInWithEmailAndPassword(email,password)
.addOnCompleteListener {task: Task<AuthResult> ->

if(!task.isSuccessful){
println("Login Failed with ${task.exception}")
_signInStatus.postValue(ResultOf.Success("Login Failed with ${task.exception}"))
}else{
_signInStatus.postValue(ResultOf.Success("Login Successful"))

}
loading.postValue(false)
}

}

sign out:

auth?.let {authentation ->
authentation.signOut()
_signOutStatus.postValue(ResultOf.Success("Signout Successful"))
loading.postValue(false)
}

Upload doc:

val ref = storageReference
.child("/uploadedDocs/"
+ UUID.randomUUID().toString())
val uploadTask = ref.putFile(selectedImageUri)
val urlTask = uploadTask.continueWithTask(Continuation<UploadTask.TaskSnapshot, Task<Uri>> { task ->
if (!task.isSuccessful) {
task.exception?.let {
throw it
}
}
return@Continuation ref.downloadUrl
})?.addOnCompleteListener { task ->
if (task.isSuccessful) {
val downloadUri = task.result
println
("Downloaded URL: is ${downloadUri.toString()}")
var downloadUrl = downloadUri.toString() //Return URL of uploaded doc
_uploadDocResult.postValue(ResultOf.Success(downloadUrl))
loading.postValue(false)
// addUploadRecordToDb(downloadUri.toString())
} else {
_uploadDocResult.postValue(ResultOf.Success("Upload Failed"))
loading.postValue(false)
}
}?.addOnFailureListener{
_uploadDocResult.postValue(ResultOf.Success("Upload Failed"))
loading.postValue(false)
}

Save Single row of Data to Realtime DB:

val id: String? = reference.push().key   //Creates unique ID to represent a row


reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(@NonNull snapshot: DataSnapshot) {
// inside the method of on Data change we are setting
// our object class to our database reference.
// data base reference will sends data to firebase.
if (id != null) {
reference.child(id).setValue(taxInfo) //Set the Dataclass object to save the data
}

_saveResult.postValue(ResultOf.Success("Data Saved Successfully"))
loading.postValue(false)
}

override fun onCancelled(@NonNull error: DatabaseError) {
// if the data is not added or it is cancelled then
// we are displaying a failure toast message.
_saveResult.postValue(ResultOf.Success("Data Save Failed"))
loading.postValue(false)
}
})

Read Data From DB:

var checkUser: Query = reference.orderByChild("employeeEmail").equalTo(email)

checkUser.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (postSnapshot in dataSnapshot.children) {
val taxInfo= postSnapshot.getValue(TaxInfo::class.java)
if (taxInfo != null) {
taxInfoList.add(taxInfo)
}
}
_taxInfoMutableLiveDataList.postValue(ResultOf.Success(taxInfoList))

}

DataModel:

data class TaxInfo(val employeeEmail : String = "",val taxDetailType:String = "",val taxDetailAmount:String = "",val uploadUrl:String ="")

Note: FireBase requires us to intialize dataclass variables with default values in Kotlin. Otherwise it throws an error. Make sure to initialize variables in data class to default values.

Github link for source code:

Dependencies:

implementation platform('com.google.firebase:firebase-bom:26.5.0')

// Declare the dependency for the Firebase Authentication library
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.firebase:firebase-storage:19.2.1'
// Declare the dependency for the Realtime Database library
// When using the BoM, you don't specify versions in Firebase library dependencies
implementation 'com.google.firebase:firebase-database-ktx'

Google play services dependency:

classpath 'com.google.gms:google-services:4.3.5'

Screen shots for App:

Brief Introduction of FireBase:

Firebase is a backend platform for building Web, Android and IOS applications. It offers real time database, different APIs, multiple authentication types and hosting platform.

Firebase is a Backend-as-a-Service, and it is a real-time database which is basically designed for mobile applications.

In the era of rapid prototyping, we can get bright ideas, but sometimes they are not applicable if they take too much work. Often, the back-end is the limiting factor — many considerations never apply to server-side coding due to lack of knowledge or time.

Firebase is a Backend-as-a-Service(BaaS) which started as a YC11 startup. It grew up into a next-generation app-development platform on Google Cloud Platform. Firebase (a NoSQLjSON database) is a real-time database that allows storing a list of objects in the form of a tree. We can synchronize data between different devices.

The below are the features provided by Firebase

FireBase features

We can use any of these services with the help of the Firebase Android SDK to create android apps without writing any server code.

The most important of the above services are Authentication, Realtime Data Base which are basic .

Advantages of FireBase:

  • Firebase manages real-time data in the database. So, it easily and quickly exchanges the data to and from the database. Hence, for developing mobile apps such as live streaming, chat messaging, etc., we can use Firebase.
  • Firebase allows syncing real-time data across all devices — iOS, Android, and Web — without refreshing the screen.
  • Firebase provides integration to Google Advertising, AdMob, Data Studio, BigQuery DoubleClick, Play Store, and Slack to develop our apps with efficient and accurate management and maintenance.
  • Everything from databases, analytics to crash reports are included in Firebase. So, the app development team can stay focused on improving the user experience.
  • Firebase applications can be deployed over a secured connection to the firebase server.
  • Firebase offers a simple control dashboard.
  • It offers a number of useful services to choose from.
  • There is no server infrastructure required to power apps with data.
  • It has JSON storage, which means no barrier between data and objects.
  • Firebase is serverless.

Add Firebase to your Android project:

You can connect your Android app to Firebase using one of the following options:

  • Option 1: (recommended) Use the Firebase console setup workflow.
  • Option 2: Use the Android Studio Firebase Assistant (may require additional configuration).

More info in the below link:

--

--