Open In App

How to Create a Medicine Tracker Android App with Firebase?

Last Updated : 01 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

A medicine tracker app can be a useful tool for individuals who need to take multiple medications on a regular basis. It can help users track when they need to take their medications and provide alerts and reminders to ensure they don’t miss a dose. This article will look at how to build a medicine tracker app using Kotlin and Firebase. A sample video is given below to get an idea about what we are going to do in this article.

Step by Step Implementation

Step 1: Create a New Project in Android Studio

To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.

Step 2: Set up the development environment

Add firebase real-time database dependency in build.gradle(app) file

implementation 'com.google.firebase:firebase-database-ktx:20.1.0'

Add View binding inside android{} block in build.gradle(app) file

XML




buildFeatures {
        viewBinding = true
    }


Step 3: Create a new Firebase Project

Have a look at Adding Firebase to Android App also add a Real-time database to your firebase project.

Step 4: Design the app’s user interface

Navigate to the app > res > layout > activity_main.xml and add the below code to that file. Below is the code for the activity_main.xml file. Comments are added inside the code to understand the code in more detail.

activity_main.xml

XML




<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
  
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:listitem="@layout/medicine_layout">
  
    </androidx.recyclerview.widget.RecyclerView>
  
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floatingActionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginEnd="15dp"
        android:layout_marginBottom="15dp"
        app:srcCompat="@android:drawable/ic_input_add"
        tools:layout_editor_absoluteX="254dp"
        tools:layout_editor_absoluteY="360dp" />
  
</androidx.constraintlayout.widget.ConstraintLayout>


activity_medicine_add.xml 

New Activity to Add Medicines

XML




<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MedicineAddActivity">
  
    <EditText
        android:id="@+id/etMedicineName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:textSize="20dp"
        android:background="@color/white"
        android:hint="Enter Medicine Name"
        android:textColor="@color/black">
    </EditText>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:weightSum="100"
        android:orientation="horizontal">
  
        <TextView
            android:id="@+id/etMedicineTime"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:text="Medicine Time"
            android:textSize="20dp"
            android:layout_weight="50"
            android:textAlignment="center"
            android:textColor="@color/black"
            android:padding="10dp"
            android:layout_margin="10dp">
        </TextView>
  
        <ImageView
            android:id="@+id/selectTime"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_weight="50"
            android:padding="10dp"
            android:layout_margin="10dp"
            android:src="@drawable/ic_baseline_access_time_24">
        </ImageView>
  
    </LinearLayout>
    
    <Button
        android:id="@+id/save"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Save">
    </Button>
    
</LinearLayout>


medicine_layout.xml

Layout File for RecyclerView

XML




<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MedicineAddActivity">
    
    <EditText
        android:id="@+id/etMedicineName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:textSize="20dp"
        android:background="@color/white"
        android:hint="Enter Medicine Name"
        android:textColor="@color/black">
    </EditText>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:weightSum="100"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/etMedicineTime"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:text="Medicine Time"
            android:textSize="20dp"
            android:layout_weight="50"
            android:textAlignment="center"
            android:textColor="@color/black"
            android:padding="10dp"
            android:layout_margin="10dp">
        </TextView>
        <ImageView
            android:id="@+id/selectTime"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_weight="50"
            android:padding="10dp"
            android:layout_margin="10dp"
            android:src="@drawable/ic_baseline_access_time_24">
        </ImageView>
    </LinearLayout>
    
    <Button
        android:id="@+id/save"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Save">
    </Button>
  
</LinearLayout>


Step 5: Create MedicineAlarmReceiver class for notifications 

This class, named “MedicineAlarmReceiver”, is a subclass of the Android class “BroadcastReceiver” and is used to receive broadcast notifications.

Kotlin




class MedicineAlarmReceiver : BroadcastReceiver() {
  
    override fun onReceive(context: Context, intent: Intent) {
        // Create the notification channel (required for Android 8.0 and higher)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // unique id for the channel
            val channelId = "medicine_reminders"
            
            // name of the channel
            val channelName = "Medicine Reminders"
            
            // importance level of the channel
            val importance = NotificationManager.IMPORTANCE_HIGH 
            
            // creating channel
            val channel =
                NotificationChannel(channelId, channelName, importance) 
                  
            // enabling lights for the channel
            channel.enableLights(true
              
            // setting light color for the channel
            channel.lightColor = Color.RED 
            
            // enabling vibration for the channel
            channel.enableVibration(true
            val notificationManager = context.getSystemService(NotificationManager::class.java)
            notificationManager?.createNotificationChannel(
                channel
            ) // registering the channel with the system
        }
  
        // Create the notification
          
        // unique id for the notification
        val notificationId = 1 
        
        // title of the notification
        val title = "Medicine Reminder" 
        
        // text of the notification
        val text = "It's time to take your medicine." 
        val intent =
            Intent(
                context,
                MainActivity::class.java
            ) // intent to launch when the notification is clicked
        val pendingIntent =
            PendingIntent.getActivity(
                context,
                0,
                intent,
                0
            ) // creating a pending intent to wrap the intent
              
        // creating the builder object
        val builder =
            NotificationCompat.Builder(context, "medicine_reminders"
                .setSmallIcon(
                    R.drawable.ic_baseline_mediation_24
                ) // setting the small icon for the notification
                .setContentTitle(title) // setting the title for the notification
                .setContentText(text) // setting the text for the notification
                .setContentIntent(pendingIntent) // attaching the pending intent to the notification
                .setAutoCancel(
                    true
                ) // setting the notification to be automatically cancelled when clicked
                .setPriority(
                    NotificationCompat.PRIORITY_HIGH
                ) // setting the priority level of the notification
  
        // Display the notification
          
        // getting the notification manager
        val notificationManager =
            NotificationManagerCompat.from(context) 
              
        // displaying the notification
        notificationManager.notify(notificationId, builder.build()) 
    }
}


Step 6: Create a data class User

Kotlin




data class User (
    val medicineName : String ,
    val time : String
        )


Step 7: Create UserAdapterClass for recycler View

Kotlin




class UserAdapter(private val list: ArrayList<User>) :
    RecyclerView.Adapter<UserAdapter.ViewHolder>() {
  
    // ViewHolder to hold reference to each item of the recycler view
    class ViewHolder(val binding: MedicineLayoutBinding) : RecyclerView.ViewHolder(binding.root) {}
  
    // inflating the layout and creating the ViewHolder when needed
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            MedicineLayoutBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
        )
    }
  
    // binding data to the view in the viewholder
    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.binding.name.text = list[position].medicineName
        holder.binding.time.text = list[position].time
    }
  
    // returning the size of the data set
    override fun getItemCount(): Int {
        return list.size
    }
}


Step 8: Create a new activity MedicineAdd and add these lines of code to it 

We will be using a TimePicker dialog in this activity in order to add medicine time.

Kotlin




class MedicineAddActivity : AppCompatActivity(), TimePickerDialog.OnTimeSetListener {
    // reference to the database 
    private lateinit var database : DatabaseReference
    // reference to the layout binding object
    private lateinit var binding: ActivityMedicineAddBinding
    // variables to store the current time
    var hours = 0
    var minutes = 0
    // variables to store the selected time
    var myHours : Int = 0
    var myMinutes : Int= 0
      
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // inflating the layout and binding it to the binding object
        binding = ActivityMedicineAddBinding.inflate(layoutInflater)
        setContentView(binding.root)
        // setting a click listener on the select time button 
        binding.selectTime.setOnClickListener{
            val cal = Calendar.getInstance()
            // getting the current time 
            hours = cal.get(Calendar.HOUR)
            minutes = cal.get(Calendar.MINUTE)
            // creating a new time picker dialog 
            val timePickerDialog = TimePickerDialog(this,this,hours,minutes,true)
            timePickerDialog.show()
        }
    }
    // method called when the user sets the time on the time picker dialog
    override fun onTimeSet(view: TimePicker?, hourOfDay: Int, minute: Int) {
        myHours = hourOfDay
        myMinutes = minute
        // updating the text view that displays the selected time
        binding.etMedicineTime.text = "$myHours:$myMinutes"
        // setting a click listener on the save button
        binding.save.setOnClickListener{
            saveData()
        }
    }
}


Step 9: Save Data in firebase real-time database 

The method starts by getting an instance of the FirebaseDatabase and getting a reference to the “Users” node in the database. The method then retrieves the value of the text from the “etMedicineName” TextView, trims it, and stores it in the variable medicineName.

Kotlin




private fun saveData() {
    // Reference to the "Users" node in the Firebase Database
    database = FirebaseDatabase.getInstance().getReference("Users")
    // Retrieve the value of the text from the "etMedicineName" TextView
    val medicineName = binding.etMedicineName.text.toString().trim()
    // Create a string with the selected time in the format "hours:minutes"
    val time = "$myHours:$myMinutes"
    // check if the medicineName is not empty
    if (medicineName.isNotEmpty()){
        // create a new User object with the 
        // entered medicine name and selected time
        val user = User(medicineName,time)
        // save the user object to the Firebase Database
        // under the "medicineName" key
        database.child(medicineName).setValue(user).addOnSuccessListener {
            // Clearing the EditText after saving the data
            binding.etMedicineName.text.clear()
            binding.etMedicineTime.text = "Select Time"
            Toast.makeText(this, "Success: Data saved to Firebase", Toast.LENGTH_SHORT).show()
        }.addOnFailureListener{
            Toast.makeText(this, "Error: Failed to save data to Firebase", Toast.LENGTH_SHORT).show()
        }
    }
    // call the setAlarm method to
    // set the alarm based on the selected time
    setAlarm()
}


Step 10: Set Alarm for medicine

The method starts by getting an instance of the AlarmManager service and creating a new Intent for the MedicineAlarmReceiver class. Then, it creates a PendingIntent that wraps the intent and requests the broadcast to be delivered to the MedicineAlarmReceiver

Kotlin




private fun setAlarm() {
       val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
       val intent = Intent(this, MedicineAlarmReceiver::class.java)
       val pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0)
 
       // Set the alarm to trigger at the specified time
       val calendar = Calendar.getInstance()
       calendar.timeInMillis = System.currentTimeMillis()
       calendar.set(Calendar.HOUR_OF_DAY, myHours)
       calendar.set(Calendar.MINUTE, myMinutes)
 
       alarmManager.setRepeating(
           AlarmManager.RTC_WAKEUP,
           calendar.timeInMillis,
           AlarmManager.INTERVAL_DAY,
           pendingIntent
       )
   }


Output:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads