How to Create a Medicine Tracker Android App with Firebase?
Last Updated :
01 Feb, 2023
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
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
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
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) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelId = "medicine_reminders"
val channelName = "Medicine Reminders"
val importance = NotificationManager.IMPORTANCE_HIGH
val channel =
NotificationChannel(channelId, channelName, importance)
channel.enableLights( true )
channel.lightColor = Color.RED
channel.enableVibration( true )
val notificationManager = context.getSystemService(NotificationManager:: class .java)
notificationManager?.createNotificationChannel(
channel
)
}
val notificationId = 1
val title = "Medicine Reminder"
val text = "It's time to take your medicine."
val intent =
Intent(
context,
MainActivity:: class .java
)
val pendingIntent =
PendingIntent.getActivity(
context,
0 ,
intent,
0
)
val builder =
NotificationCompat.Builder(context, "medicine_reminders" )
.setSmallIcon(
R.drawable.ic_baseline_mediation_24
)
.setContentTitle(title)
.setContentText(text)
.setContentIntent(pendingIntent)
.setAutoCancel(
true
)
.setPriority(
NotificationCompat.PRIORITY_HIGH
)
val notificationManager =
NotificationManagerCompat.from(context)
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>() {
class ViewHolder(val binding: MedicineLayoutBinding) : RecyclerView.ViewHolder(binding.root) {}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
MedicineLayoutBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.binding.name.text = list[position].medicineName
holder.binding.time.text = list[position].time
}
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 {
private lateinit var database : DatabaseReference
private lateinit var binding: ActivityMedicineAddBinding
var hours = 0
var minutes = 0
var myHours : Int = 0
var myMinutes : Int= 0
override fun onCreate(savedInstanceState: Bundle?) {
super .onCreate(savedInstanceState)
binding = ActivityMedicineAddBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.selectTime.setOnClickListener{
val cal = Calendar.getInstance()
hours = cal.get(Calendar.HOUR)
minutes = cal.get(Calendar.MINUTE)
val timePickerDialog = TimePickerDialog( this , this ,hours,minutes, true )
timePickerDialog.show()
}
}
override fun onTimeSet(view: TimePicker?, hourOfDay: Int, minute: Int) {
myHours = hourOfDay
myMinutes = minute
binding.etMedicineTime.text = "$myHours:$myMinutes"
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() {
database = FirebaseDatabase.getInstance().getReference( "Users" )
val medicineName = binding.etMedicineName.text.toString().trim()
val time = "$myHours:$myMinutes"
if (medicineName.isNotEmpty()){
val user = User(medicineName,time)
database.child(medicineName).setValue(user).addOnSuccessListener {
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()
}
}
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 )
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
Please Login to comment...