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