
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 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)
}
}
}


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:
Check our similar post here: Login and Signup using Firebase Authentication in Android Studio