Android Knowledge

Store Retrieve Data in Firebase Realtime Database using Kotlin in Android Studio – Easy 8 Steps!

firebase kotlin android

Table of Contents

What is Firebase Realtime Database?

Firebase is a service to applications, it provides hosting, NoSQL storage, real-time databases, social authentication, notification, and other services.

In this project, we have created a login and signup page in android studio using firebase realtime database so all our data will be saved for free! When the user signs up using a username and password gets stored in the realtime database of firebase.

For login purposes, the same credentials are checked in the firebase realtime database and if it matches with user credentials then it will lead you to the home screen otherwise it will throw an error as login failed.

Step-by-Step Implementation

Step 1: Open Android Studio, Click New Project and Choose Empty Activity.

Step 2:colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="purple_200">#FFBB86FC</color>
    <color name="purple_500">#FF6200EE</color>
    <color name="purple_700">#FF3700B3</color>
    <color name="teal_200">#FF03DAC5</color>
    <color name="teal_700">#FF018786</color>
    <color name="black">#FF000000</color>
    <color name="white">#FFFFFFFF</color>
    <color name="lavender">#8692f7</color>
   

</resources>

themes.xml

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="Theme.StoreDataRealtime" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/lavender</item>
        <item name="colorPrimaryVariant">@color/lavender</item>
        <item name="colorOnPrimary">@color/white</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_700</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color. -->
        <item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>

    <style name="roundedImageViewRounded">
        <item name="cornerFamily">rounded</item>
        <item name="cornerSize">50%</item>
    </style>

</resources>

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>

lavender_border.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <stroke
        android:width="2dp"
        android:color="@color/lavender"/>
    <corners
        android:radius="30dp"/>

</shape>

Gradle: Module

buildFeatures{
        viewBinding true
    }

implementation 'com.github.bumptech.glide:glide:4.14.2'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'

progress_layout.xml

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

    <ProgressBar
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:indeterminateTint="@color/lavender"/>

    <TextView
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="4"
        android:text="Loading..."
        android:textSize="18sp"
        android:textColor="@color/lavender"
        android:gravity="start|center_vertical"/>

</LinearLayout>

Step 3: activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    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=".MainActivity">

    <androidx.appcompat.widget.SearchView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginStart="12dp"
        android:layout_marginEnd="12dp"
        android:id="@+id/search"
        app:iconifiedByDefault="false"
        app:searchHintIcon="@null"
        app:queryHint="Search..."
        android:focusable="false"
        app:closeIcon="@drawable/ic_baseline_clear_24"
        app:searchIcon="@drawable/ic_baseline_search_24"
        android:background="@drawable/lavender_border"/>

    <androidx.recyclerview.widget.RecyclerView
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerView"
        android:layout_below="@id/search"
        android:scrollbars="vertical"/>

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:layout_margin="40dp"
        android:backgroundTint="@color/lavender"
        app:tint = "@color/white"
        android:src="@drawable/ic_baseline_add_24" />

</RelativeLayout>

Step 4: activity_upload.xml

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    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:background="@drawable/addtask"
    tools:context=".UploadActivity">

    <androidx.cardview.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="130dp"
        android:layout_marginEnd="20dp"
        android:layout_marginStart="20dp"
        app:cardCornerRadius="30dp"
        app:cardElevation="20dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_gravity="center_horizontal"
            android:background="@drawable/lavender_border"
            android:padding="20dp">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:src="@drawable/uploadimg"
                android:id="@+id/uploadImage"
                android:layout_marginTop="10dp"
                android:scaleType="fitXY"/>

            <EditText
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:id="@+id/uploadTitle"
                android:background="@drawable/lavender_border"
                android:layout_marginTop="20dp"
                android:padding="16dp"
                android:maxLines="1"
                android:hint="Enter task name"
                android:gravity="start|center_vertical"
                android:textColor="@color/lavender"/>

            <EditText
                android:layout_width="match_parent"
                android:layout_height="80dp"
                android:id="@+id/uploadDesc"
                android:background="@drawable/lavender_border"
                android:layout_marginTop="20dp"
                android:padding="16dp"
                android:hint="Enter task description"
                android:gravity="start|center_vertical"
                android:textColor="@color/lavender"/>

            <EditText
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:id="@+id/uploadPriority"
                android:background="@drawable/lavender_border"
                android:layout_marginTop="20dp"
                android:padding="16dp"
                android:hint="Enter task priority"
                android:gravity="start|center_vertical"
                android:textColor="@color/lavender"/>

            <Button
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:text="Save"
                android:id="@+id/saveButton"
                android:textSize="18sp"
                android:layout_marginTop="20dp"
                app:cornerRadius = "20dp"/>


        </LinearLayout>

    </androidx.cardview.widget.CardView>

</ScrollView>

recycler_item.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/recCard"
    android:layout_marginStart="12dp"
    android:layout_marginEnd="12dp"
    android:layout_marginHorizontal="10dp"
    android:layout_marginVertical="10dp"
    app:cardCornerRadius="20dp"
    app:cardElevation="8dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.imageview.ShapeableImageView
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:id="@+id/recImage"
            android:src="@drawable/uploadimg"
            android:layout_marginStart="10dp"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="10dp"
            android:scaleType="centerCrop"
            app:shapeAppearanceOverlay="@style/roundedImageViewRounded"/>

        <TextView
            android:layout_width="120dp"
            android:layout_height="30dp"
            android:id="@+id/recTitle"
            android:text="Title"
            android:textColor="@color/lavender"
            android:textSize="20sp"
            android:layout_marginTop="20dp"
            android:layout_marginStart="20dp"
            android:layout_toEndOf="@id/recImage"/>

        <TextView
            android:layout_width="80dp"
            android:layout_height="30dp"
            android:id="@+id/recPriority"
            android:text="priority"
            android:layout_toEndOf="@id/recTitle"
            android:layout_marginTop="20dp"
            android:layout_marginStart="90dp"
            android:textAlignment="center"
            android:textColor="@color/lavender"
            android:textSize="16sp"/>

        <TextView
            android:layout_width="140dp"
            android:layout_height="wrap_content"
            android:id="@+id/recDesc"
            android:text="desc"
            android:textColor="@color/lavender"
            android:textSize="14sp"
            android:layout_toEndOf="@id/recImage"
            android:layout_below="@id/recTitle"
            android:layout_marginStart="20dp"
            android:maxLines="1"
            android:layout_marginBottom="12dp"/>

    </RelativeLayout>

</androidx.cardview.widget.CardView>

Step 5: MainActivity.kt

package com.example.storerealkot

import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.GridLayoutManager
import com.example.storerealkot.databinding.ActivityMainBinding
import com.google.firebase.database.*
import java.util.*


class MainActivity : AppCompatActivity() {
    var databaseReference: DatabaseReference? = null
    var eventListener: ValueEventListener? = null
    private lateinit var dataList: ArrayList<DataClass>
    private lateinit var adapter: MyAdapter
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val gridLayoutManager = GridLayoutManager(this@MainActivity, 1)
        binding.recyclerView.layoutManager = gridLayoutManager
        binding.search.clearFocus()

        val builder = AlertDialog.Builder(this@MainActivity)
        builder.setCancelable(false)
        builder.setView(R.layout.progress_layout)
        val dialog = builder.create()
        dialog.show()

        dataList = ArrayList()
        adapter = MyAdapter(this@MainActivity, dataList)
        binding.recyclerView.adapter = adapter
        databaseReference = FirebaseDatabase.getInstance().getReference("Todo List")
        dialog.show()

        eventListener = databaseReference!!.addValueEventListener(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                dataList.clear()
                for (itemSnapshot in snapshot.children) {
                    val dataClass = itemSnapshot.getValue(DataClass::class.java)
                    if (dataClass != null) {
                        dataList.add(dataClass)
                    }
                }
                adapter.notifyDataSetChanged()
                dialog.dismiss()
            }

            override fun onCancelled(error: DatabaseError) {
                dialog.dismiss()
            }
        })

        binding.fab.setOnClickListener(View.OnClickListener {
            val intent = Intent(this@MainActivity, UploadActivity::class.java)
            startActivity(intent)
        })

        binding.search.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String): Boolean {
                return false
            }

            override fun onQueryTextChange(newText: String): Boolean {
                searchList(newText)
                return true
            }
        })
    }
    fun searchList(text: String) {
        val searchList = java.util.ArrayList<DataClass>()
        for (dataClass in dataList) {
            if (dataClass.dataTitle?.lowercase()
                    ?.contains(text.lowercase(Locale.getDefault())) == true
            ) {
                searchList.add(dataClass)
            }
        }
        adapter.searchDataList(searchList)
    }
}

Step 6: DataClass.kt

package com.example.todolist

class DataClass {
    var dataTitle: String? = null
    var dataDesc: String? = null
    var dataPriority: String? = null
    var dataImage: String? = null

    constructor(dataTitle: String?, dataDesc: String?, dataPriority: String?, dataImage: String?){
        this.dataTitle = dataTitle
        this.dataDesc = dataDesc
        this.dataPriority = dataPriority
        this.dataImage = dataImage
    }
constructor()
{}
}

Step 7: UploadActivity.kt

package com.example.todolist

import android.content.Intent
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import com.example.todolist.databinding.ActivityUploadBinding
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.storage.FirebaseStorage
import java.net.URI
import java.text.DateFormat
import java.util.Calendar

class UploadActivity : AppCompatActivity() {

    private lateinit var binding: ActivityUploadBinding
    var imageURL: String? = null
    var uri: Uri? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityUploadBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val activityResultLauncher = registerForActivityResult<Intent, ActivityResult>(
            ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == RESULT_OK) {
                val data = result.data
                uri = data!!.data
                binding.uploadImage.setImageURI(uri)
            } else {
                Toast.makeText(this@UploadActivity, "No Image Selected", Toast.LENGTH_SHORT).show()
            }
        }
        binding.uploadImage.setOnClickListener {
            val photoPicker = Intent(Intent.ACTION_PICK)
            photoPicker.type = "image/*"
            activityResultLauncher.launch(photoPicker)
        }
        binding.saveButton.setOnClickListener {
            saveData()
        }
    }
    private fun saveData(){
        val storageReference = FirebaseStorage.getInstance().reference.child("Task Images")
            .child(uri!!.lastPathSegment!!)

        val builder = AlertDialog.Builder(this@UploadActivity)
        builder.setCancelable(false)
        builder.setView(R.layout.progress_layout)
        val dialog = builder.create()
        dialog.show()

        storageReference.putFile(uri!!).addOnSuccessListener { taskSnapshot ->
            val uriTask = taskSnapshot.storage.downloadUrl
            while (!uriTask.isComplete);
            val urlImage = uriTask.result
            imageURL = urlImage.toString()
            uploadData()
            dialog.dismiss()
        }.addOnFailureListener {
            dialog.dismiss()
        }
    }
    private fun uploadData(){
        val title = binding.uploadTitle.text.toString()
        val desc = binding.uploadDesc.text.toString()
        val priority = binding.uploadPriority.text.toString()

        val dataClass = DataClass(title, desc, priority, imageURL)
        val currentDate = DateFormat.getDateTimeInstance().format(Calendar.getInstance().time)

        FirebaseDatabase.getInstance().getReference("Todo List").child(currentDate)
            .setValue(dataClass).addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    Toast.makeText(this@UploadActivity, "Saved", Toast.LENGTH_SHORT).show()
                    finish()
                }
            }.addOnFailureListener { e ->
                Toast.makeText(
                    this@UploadActivity, e.message.toString(), Toast.LENGTH_SHORT).show()
            }
    }
}

Step 8: MyAdapter.kt

package com.example.storerealkot

import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide

class MyAdapter(private val context: Context, private var dataList: List<DataClass>) : RecyclerView.Adapter<MyViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view: View = LayoutInflater.from(parent.context).inflate(R.layout.recycler_item, parent, false)
        return MyViewHolder(view)
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        Glide.with(context).load(dataList[position].dataImage)
            .into(holder.recImage)
        holder.recTitle.text = dataList[position].dataTitle
        holder.recDesc.text = dataList[position].dataDesc
        holder.recPriority.text = dataList[position].dataPriority

        holder.recCard.setOnClickListener {
            val intent = Intent(context, DetailActivity::class.java)
            intent.putExtra("Image", dataList[holder.adapterPosition].dataImage)
            intent.putExtra("Description", dataList[holder.adapterPosition].dataDesc)
            intent.putExtra("Title", dataList[holder.adapterPosition].dataTitle)
            intent.putExtra("Priority", dataList[holder.adapterPosition].dataPriority)
            context.startActivity(intent)
        }

    }

    override fun getItemCount(): Int {
        return dataList.size
    }
    fun searchDataList(searchList: List<DataClass>) {
        dataList = searchList
        notifyDataSetChanged()
    }
}

class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    var recImage: ImageView
    var recTitle: TextView
    var recDesc: TextView
    var recPriority: TextView
    var recCard: CardView

    init {
        recImage = itemView.findViewById(R.id.recImage)
        recTitle = itemView.findViewById(R.id.recTitle)
        recDesc = itemView.findViewById(R.id.recDesc)
        recPriority = itemView.findViewById(R.id.recPriority)
        recCard = itemView.findViewById(R.id.recCard)
    }
}

activity_detail.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:orientation="vertical"
    tools:context=".DetailActivity">

    <TextView
        android:id="@+id/detailTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Title"
        android:layout_marginTop="14dp"
        android:textSize="24sp"
        android:layout_gravity="center"
        android:textColor="@color/lavender"
        android:layout_marginBottom="12dp"/>

    <ImageView
        android:layout_width="400dp"
        android:layout_height="200dp"
        android:id="@+id/detailImage"
        android:padding="8dp"
        android:layout_gravity="center"
        android:src="@drawable/uploadimg"
        android:scaleType="fitXY" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:padding="20dp"
        android:text="Priority"
        android:layout_gravity="center"
        android:id="@+id/detailPriority"
        android:textColor="@color/lavender"
        android:textSize="18sp"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:padding="20dp"
        android:text="Description"
        android:layout_gravity="center"
        android:id="@+id/detailDesc"
        android:textColor="@color/lavender"
        android:textSize="18sp"/>

</LinearLayout>

DetailActivity.kt

package com.example.storerealkot

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.bumptech.glide.Glide
import com.example.storerealkot.databinding.ActivityDetailBinding

class DetailActivity : AppCompatActivity() {
    var imageUrl = ""
    private lateinit var binding: ActivityDetailBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityDetailBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val bundle = intent.extras
        if (bundle != null) {
            binding.detailDesc.text = bundle.getString("Description")
            binding.detailTitle.text = bundle.getString("Title")
            binding.detailPriority.text = bundle.getString("Priority")
            imageUrl = bundle.getString("Image")!!
            Glide.with(this).load(bundle.getString("Image"))
                .into(binding.detailImage)
        }
    }
}

Output

firebase kotlin android
retrieve firebase data

AK Bonus Points

If you have any queries or errors, please feel free to comment below 🙂

For detailed steps, watch our youtube video: Store Data in Firebase Realtime Database in Android Studio using Kotlin

Retrieve Data from Firebase Realtime Database in Android Studio using Kotlin:

https://youtu.be/vVs4slEQ5fs

Check our similar post here: Login and Signup using Firebase Authentication in Android Studio