Learn to use the Well being Join Android API to create an app that reads and writes well being information and manages well being permissions.
Well being Join is an Android API and Platform. For builders, it offers a single interface for dealing with customers’ well being information. For customers, it’s a central place to get an summary of well being information and permissions granted to different apps.
On this tutorial, you’ll study Well being Join by making a pattern app — fitLogger. In doing so, you’ll study the next within the context of the Well being Join Android API:
- Dealing with permissions
- Writing information
- Studying information
Getting Began
Organising an Emulator to Take a look at the Well being Join API
Except you’re utilizing an actual gadget to construct and run this app, you’ll want an emulator with Play Retailer assist. To create an emulator, go to Instruments ▸ Gadget Supervisor and click on Create gadget. From the listing of units, select a tool with an icon within the Play Retailer column.
In the course of the subsequent steps choose a system picture, select an AVD identify and click on End.
Downloading and Exploring the Starter Challenge
Use the Obtain Supplies button on the prime or backside of this tutorial to obtain the starter challenge. Open the challenge in Android Studio Bumblebee (2021.1.1) or later. Go to Run ▸ Run ´app´.
To maintain the give attention to Well being Join, the required structure for this tutorial is created within the activity_main.xml file. You’ll join this structure with the precise performance to learn and write the well being information.
Introducing Well being Join
Many well being and health apps run on Android. Google Match is the same app made by Google. These apps can acquire numerous information and deal with permissions. Customers can use one app to retailer well being info and one other for health monitoring. With information unfold amongst a number of apps, customers should go into many apps to get an summary. Additionally, privateness is usually a fear when information is on a number of apps.
Well being Join is an API and a platform. As an API, it helps builders use a single interface. As a platform, it helps customers have an summary of all the things in a single place.
Well being Join offers the next options to builders and customers:
Privateness Controls
Android OS ensures shopper apps request permissions earlier than accessing information or {hardware} on the gadget. Well being Join offers built-in permission controls. Builders request permissions by the API, and customers can see the Well being Join app to overview permission requests and grant or deny permissions.
Customers can use the Well being Join app to find out which apps have permission to entry well being information. If wanted, they will revoke these permissions by the app. Well being Join ensures that shopper apps can solely learn information when the app is operating within the foreground.
Storage
Well being Join offers on-device storage, so all the information is in a central place. As a developer, it can save you the information utilizing the API and retrieve the information saved by one other app.
A person can use the platform to get an summary of well being and health information. The platform can even delete information.
Knowledge Varieties
Well being Join affords an intensive vary of information sorts to let customers observe forms of health- and fitness-related information. Varied apps can contribute or devour information within the Android ecosystem by having unified information sorts.
Key information classes:
- Exercise: This captures any exercise by a person, together with operating, swimming, sleeping and meditation.
- Physique Measurement: That is frequent information associated to the physique, together with peak, weight and BMR (Basal Metabolic Charge).
- Cycle Monitoring: Knowledge recorded right here embody menstrual cycles and different associated information factors.
- Vitamin: Hydration and diet information sorts, together with water, energy, sugar and magnesium.
- Sleep: Interval information associated to a person’s size and kind of sleep.
- Vitals: Important details about the person’s common well being, together with blood glucose, physique temperature and blood oxygen saturation is recorded beneath this class.
Well being Join APK
The Well being Join APK must be accessible on the shopper’s gadget. It incorporates the Permissions Administration and Knowledge Administration elements. It is going to deal with requests despatched by any utility utilizing the Well being Join SDK.
Open the Play Retailer in your gadget or emulator. Should you’re utilizing a brand new emulator, signal into your Google account. Then, seek for Well being Join by Android and set up the app.
Dealing with Dependencies
Now that you’ve got an summary of Well being Join, it’s coding time!
Add the next dependency on the backside of the module’s construct.gradle file:
implementation 'androidx.well being:health-connect-client:1.0.0-alpha03'
By together with this SDK in your utility, you should use the Well being Join API. Click on the construct button to obtain dependencies and recompile the challenge.
Dealing with Permissions and Privateness Coverage
Earlier than you possibly can learn or write information, it’s essential to declare all of the permissions your app will use. Create a brand new useful resource file named health_permissions.xml beneath res/values. Add the next permissions:
<assets>
<array identify="health_permissions">
<merchandise>androidx.well being.permission.Steps.READ</merchandise>
<merchandise>androidx.well being.permission.Steps.WRITE</merchandise>
<merchandise>androidx.well being.permission.TotalCaloriesBurned.READ</merchandise>
<merchandise>androidx.well being.permission.TotalCaloriesBurned.WRITE</merchandise>
</array>
</assets>
Every merchandise represents a permission your app will use.
Well being Join wants the shopper app to outline the coverage on dealing with privateness and information.
Go to File ▸ New ▸ Exercise ▸ Empty Exercise. Enter PrivacyPolicyActivity for Exercise Title and click on End.
Open activity_privacy_policy.xml from the structure listing and add the next code contained in the ConstraintLayout
tag:
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="16sp"
android:layout_margin="24dp"
android:textual content="@string/privacy_policy" />
Add the next within the strings.xml file:
<string identify="privacy_policy">Lorem ipsum dolor sit amet, consectetur adipiscing elit....</string>
Now, in AndroidManifest.xml, change the auto-generated component for PrivacyPolicyActivity
with the next:
<exercise
android:exported="true"
android:identify=".PrivacyPolicyActivity">
<intent-filter>
<motion android:identify="androidx.well being.ACTION_SHOW_PERMISSIONS_RATIONALE"/>
</intent-filter>
<meta-data android:identify="health_permissions" android:useful resource="@array/health_permissions" />
</exercise>
Right here’s what’s occurring:
- You created a brand new exercise
PrivacyPolicyActivity
. - Within the structure file for the exercise, you outlined a dummy privateness coverage.
- You then declared the exercise within the manifest so your app can deal with this intent and show a privateness coverage explaining how customers’ information is dealt with.
Now, add the next features after onCreate
inside MainActivity.kt:
personal enjoyable checkPermissionsAndRun() {
// 1
val shopper = HealthConnectClient.getOrCreate(this)
// 2
val permissionsSet = setOf(
Permission.createWritePermission(StepsRecord::class),
Permission.createReadPermission(StepsRecord::class),
Permission.createWritePermission(TotalCaloriesBurnedRecord::class),
Permission.createReadPermission(TotalCaloriesBurnedRecord::class),
)
// 3
// Create the permissions launcher.
val requestPermissionActivityContract = shopper
.permissionController
.createRequestPermissionActivityContract()
val requestPermissions = registerForActivityResult(
requestPermissionActivityContract
) { granted ->
if (granted.containsAll(permissionsSet)) {
// Permissions efficiently granted
lifecycleScope.launch {
onPermissionAvailable(shopper)
}
} else {
Toast.makeText(
this, "Permissions not granted", Toast.LENGTH_SHORT
).present()
}
}
// 4
lifecycleScope.launch {
val granted = shopper.permissionController
.getGrantedPermissions(permissionsSet)
if (granted.containsAll(permissionsSet)) {
// Permissions already granted
onPermissionAvailable(shopper)
} else {
// Permissions not granted, request permissions.
requestPermissions.launch(permissionsSet)
}
}
}
personal droop enjoyable onPermissionAvailable(shopper: HealthConnectClient) {
// todo: learn information
}
Be aware: Whereas importing dependencies, there are numerous import choices for Permission. Please select androidx.well being.join.shopper.permission
.
Right here’s what’s occurring in checkPermissionsAndRun
:
- You to start with come up with a
HealthConnectClient
object.getOrCreate
creates a brand new occasion or returns an present one if it’s accessible. - Create a set of permissions with required information sorts to request permissions inside your utility. Permissions in these units have to be declared within the health_permissions useful resource array.
- Create a request permission launcher. On launch, customers will probably be prompted for permissions declared within the health_permissions useful resource array.
- Lastly, by
HealthConnectClient
, you verify whether or not you could have the required permissions. If permissions aren’t accessible, you request permissions byrequestPermissions
launcher.
onPermissionAvailable
is known as when you could have all required permissions. At this level, it’s potential to learn or write information.
Add the next after the closing utility
tag inside AndroidManifest.xml:
<queries>
<package deal android:identify="com.google.android.apps.healthdata" />
</queries>
This checks whether or not Well being Join APK is put in.
Lastly, inside onCreate
in MainActivity.kt, change // Your code
with the next code:
if (HealthConnectClient.isAvailable(this)) {
// Well being Join is on the market
checkPermissionsAndRun()
} else {
Toast.makeText(
this, "Well being Join isn't accessible", Toast.LENGTH_SHORT
).present()
}
Right here’s what’s occurring:
- By
HealthConnectClient
, you verify whether or not Well being Join is on the market. - Whether it is accessible, you verify required permissions.
You present a Toast
to the person, if Well being Join isn’t accessible.
That’s it! You’ve built-in Well being Join within the app and might request all required permissions. Give it a attempt by operating the app.
Writing Knowledge
Inserting Information
Add the next code after onPermissionAvailable
.
personal enjoyable insertData(shopper: HealthConnectClient, steps: Lengthy, caloriesBurned: Double) {
// 1
val startTime = ZonedDateTime.now().minusSeconds(1).toInstant()
val endTime = ZonedDateTime.now().toInstant()
// 2
val data = listOf(
StepsRecord(
rely = steps,
startTime = startTime,
endTime = endTime,
startZoneOffset = null,
endZoneOffset = null,
),
TotalCaloriesBurnedRecord(
power = Power.energy(caloriesBurned),
startTime = startTime,
endTime = endTime,
startZoneOffset = null,
endZoneOffset = null,
)
)
// 3
lifecycleScope.launch {
val insertRecords = shopper.insertRecords(data)
if (insertRecords.recordUidsList.isNotEmpty()) {
runOnUiThread{
Toast.makeText(
this@MainActivity,
"Information inserted efficiently",
Toast.LENGTH_SHORT
).present()
}
}
}
}
With this replace,
- You’re making a time vary with a begin and finish. You file the information in a small interval. This manner you possibly can insert the information a number of occasions in a day.
- Adopted by one other listing that incorporates
StepsRecord
andTotalCaloriesBurnedRecord
data. - Then lastly, you insert the created file by the
HealthConnectClient
occasion.recordUidsList
incorporates theuid
s of inserted data. When the listing isn’t empty, you’re displaying a hit message to the person.
Now, on the finish of onCreate
within the MainActivity.kt, add the next code:
val stepsEditText = findViewById<EditText>(R.id.stepsEditText)
val caloriesEditText = findViewById<EditText>(R.id.caloriesEditText)
findViewById<Button>(R.id.submit).setOnClickListener {
val steps = stepsEditText.textual content.toString().toLong()
val energy = caloriesEditText.textual content.toString().toDouble()
val shopper = HealthConnectClient.getOrCreate(this)
insertData(shopper, steps, energy)
// clear enter fields after insertion and shut the keyboard
stepsEditText.textual content.clear()
caloriesEditText.textual content.clear()
caloriesEditText.onEditorAction(EditorInfo.IME_ACTION_DONE)
}
Within the code above, when a person faucets Button, you learn enter values and save them with insertData()
. You then clear enter fields and shut the keyboard.
Construct and Run
That’s all it’s essential to do to put in writing information by the Well being Join API. Run the challenge, enter values and faucet the button.
Studying Knowledge
You may learn information in two methods utilizing HealthConnectClient.
-
ReadRecordsRequest
: Learn data decided by time vary and different filters. You’ll use this technique to learn the every day steps rely and energy consumption. -
AggregateRequest
: Learn aggregations for a givenAggregateMetric
. You’ll use this technique to learn month-to-month step counts and caloric intakes.
Studying Knowledge by a ReadRecordsRequest
In MainActivity.kt, add the next after insertData()
:
personal droop enjoyable readDailyRecords(shopper: HealthConnectClient) {
// 1
val right now = ZonedDateTime.now()
val startOfDay = right now.truncatedTo(ChronoUnit.DAYS)
val timeRangeFilter = TimeRangeFilter.between(
startOfDay.toLocalDateTime(),
right now.toLocalDateTime()
)
// 2
val stepsRecordRequest = ReadRecordsRequest(StepsRecord::class, timeRangeFilter)
val numberOfStepsToday = shopper.readRecords(stepsRecordRequest)
.data
.sumOf { it.rely }
val stepsTextView = findViewById<TextView>(R.id.stepsTodayValue)
stepsTextView.textual content = numberOfStepsToday.toString()
// 3
val caloriesRecordRequest = ReadRecordsRequest(
TotalCaloriesBurnedRecord::class,
timeRangeFilter
)
val caloriesBurnedToday = shopper.readRecords(caloriesRecordRequest)
.data
.sumOf { it.power.inCalories }
val caloriesTextView = findViewById<TextView>(R.id.caloriesTodayValue)
caloriesTextView.textual content = caloriesBurnedToday.toString()
}
And now the breakdown:
- You create a
TimeRangeFilter
from the beginning of the day till now. - You then create a
ReadRecordRequest
forStepsRecord
. By theHealthConnectClient
occasion, you learn data and get the sum. You get the sum as a result of there may be many data for steps taken right now. Lastly, you show the every day steps rely. - This is similar as Step 2, however the
ReadRecordsRequest
is forTotalCaloriesBurnedRecord
.
Studying Knowledge by an AggregateRequest
Add the next technique on the backside of MainActivity:
personal droop enjoyable readAggregatedData(shopper: HealthConnectClient) {
// 1
val right now = ZonedDateTime.now()
val startOfDayOfThisMonth = right now.withDayOfMonth(1)
.truncatedTo(ChronoUnit.DAYS)
val elapsedDaysInMonth = Period.between(startOfDayOfThisMonth, right now)
.toDays() + 1
val timeRangeFilter = TimeRangeFilter.between(
startOfDayOfThisMonth.toInstant(),
right now.toInstant()
)
// 2
val information = shopper.mixture(
AggregateRequest(
metrics = setOf(
StepsRecord.COUNT_TOTAL,
TotalCaloriesBurnedRecord.ENERGY_TOTAL
),
timeRangeFilter = timeRangeFilter,
)
)
// 3
val steps = information[StepsRecord.COUNT_TOTAL] ?: 0
val averageSteps = steps / elapsedDaysInMonth
val stepsAverageTextView = findViewById<TextView>(R.id.stepsAverageValue)
stepsAverageTextView.textual content = averageSteps.toString()
// 4
val caloriesBurned = information[TotalCaloriesBurnedRecord.ENERGY_TOTAL]
?.inCalories ?: 0.0
val averageCaloriesBurned = caloriesBurned / elapsedDaysInMonth
val caloriesAverageTextView = findViewById<TextView>(
R.id.caloriesAverageValue
)
caloriesAverageTextView.textual content = getString(R.string.format_calories_average)
.format(averageCaloriesBurned)
}
Be aware: Whereas importing dependencies, there are numerous import choices for Period. Please select java.time
.
Right here’s what’s occurring:
- You’re making a
TimeRangeFilter
from the beginning of the month till now. Additionally, you’re calculating the times elapsed within the month so you possibly can calculate the typical. - You’re making an
mixture
request byHealthConnectClient
with a set of measurements to get the full steps and energy inside a selected time vary. The good thing about aggregated information is it contains primary aggregations or aggregating information into buckets. - You’re calculating
averageSteps
and updating the structure. - You’re calculating
averageCaloriesBurned
and updating the structure. For a greater UI, you’re rounding the calorie values as much as two decimals.
Add the next within the strings.xml file.
<string identify="format_calories_average">%.2f</string>
You’re virtually there. You now have features that learn information, however it’s essential to join a number of ultimate dots.
Add one other technique within the MainActivity.kt:
personal droop enjoyable readData(shopper: HealthConnectClient) {
readDailyRecords(shopper)
readAggregatedData(shopper)
}
This helper operate instructions each features you created above to learn information.
Now, inside onPermissionAvailable
, change // todo: learn information
with the next.
readData(shopper)
By doing so, you possibly can learn the information and replace the structure as quickly as you could have permissions accessible.
Lastly, add the next on the finish of the lifecycleScope.launch {
block, inside insertData
:
readData(shopper)
It will make sure you present up to date information after a person inserts new information.
Construct and Run
You’re executed! Construct and run the app to see the consequence. Now you can write information and likewise see your present information.
The place to Go From Right here?
Congratulations! You’ve discovered about Well being Join by making a easy app. Now you could have one much less excuse to get fitter and more healthy. Use the Obtain Supplies button on the prime or backside of this text to obtain the ultimate challenge.
You may take a number of steps to enhance your app: