Learn to use the Well being Join Android API to create an app that reads and writes well being knowledge and manages well being permissions.
Well being Join is an Android API and Platform. For builders, it supplies a single interface for dealing with customers’ well being knowledge. For customers, it’s a central place to get an outline of well being knowledge and permissions granted to different apps.
On this tutorial, you’ll find out about 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 knowledge
- Studying knowledge
Getting Began
Organising an Emulator to Check the Well being Join API
Except you’re utilizing an actual system to construct and run this app, you’ll want an emulator with Play Retailer assist. To create an emulator, go to Instruments ▸ Machine Supervisor and click on Create system. From the listing of units, select a tool with an icon within the Play Retailer column.
Throughout the subsequent steps choose a system picture, select an AVD title and click on End.
Downloading and Exploring the Starter Mission
Use the Obtain Supplies button on the prime or backside of this tutorial to obtain the starter venture. Open the venture in Android Studio Bumblebee (2021.1.1) or later. Go to Run ▸ Run ´app´.
To maintain the concentrate on Well being Join, the required format for this tutorial is created within the activity_main.xml file. You’ll join this format with the precise performance to learn and write the well being knowledge.
Introducing Well being Join
Many well being and health apps run on Android. Google Match is an identical app made by Google. These apps can acquire numerous knowledge and deal with permissions. Customers can use one app to retailer well being info and one other for health monitoring. With knowledge unfold amongst a number of apps, customers should go into many apps to get an outline. Additionally, privateness could be a fear when knowledge 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 outline of the whole lot in a single place.
Well being Join supplies the next options to builders and customers:
Privateness Controls
Android OS ensures shopper apps request permissions earlier than accessing knowledge or {hardware} on the system. Well being Join supplies built-in permission controls. Builders request permissions by way of the API, and customers can see the Well being Join app to evaluation 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 knowledge. If wanted, they will revoke these permissions by way of the app. Well being Join ensures that shopper apps can solely learn knowledge when the app is working within the foreground.
Storage
Well being Join supplies on-device storage, so all the info is in a central place. As a developer, it can save you the info utilizing the API and retrieve the info saved by one other app.
A person can use the platform to get an outline of well being and health knowledge. The platform may delete knowledge.
Knowledge Varieties
Well being Join presents an intensive vary of knowledge varieties to let customers observe sorts of health- and fitness-related knowledge. Varied apps can contribute or devour knowledge within the Android ecosystem by having unified knowledge varieties.
Key knowledge classes:
- Exercise: This captures any exercise by a person, together with working, swimming, sleeping and meditation.
- Physique Measurement: That is widespread knowledge associated to the physique, together with peak, weight and BMR (Basal Metabolic Fee).
- Cycle Monitoring: Knowledge recorded right here embrace menstrual cycles and different associated knowledge factors.
- Diet: Hydration and diet knowledge varieties, together with water, energy, sugar and magnesium.
- Sleep: Interval knowledge associated to a person’s size and kind of sleep.
- Vitals: Important details about the person’s basic 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 system. It accommodates the Permissions Administration and Knowledge Administration elements. It’s going to deal with requests despatched by any utility utilizing the Well being Join SDK.
Open the Play Retailer in your system 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 an outline 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 need to use the Well being Join API. Click on the construct button to obtain dependencies and recompile the venture.
Dealing with Permissions and Privateness Coverage
Earlier than you’ll be able to learn or write knowledge, you want 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 title="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 knowledge.
Go to File â–¸ New â–¸ Exercise â–¸ Empty Exercise. Enter PrivacyPolicyActivity for Exercise Identify and click on End.
Open activity_privacy_policy.xml from the format 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 title="privacy_policy">Lorem ipsum dolor sit amet, consectetur adipiscing elit....</string>
Now, in AndroidManifest.xml, exchange the auto-generated component for PrivacyPolicyActivity
with the next:
<exercise
android:exported="true"
android:title=".PrivacyPolicyActivity">
<intent-filter>
<motion android:title="androidx.well being.ACTION_SHOW_PERMISSIONS_RATIONALE"/>
</intent-filter>
<meta-data android:title="health_permissions" android:useful resource="@array/health_permissions" />
</exercise>
Right here’s what’s occurring:
- You created a brand new exercise
PrivacyPolicyActivity
. - Within the format 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’ knowledge 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 knowledge
}
Word: Whereas importing dependencies, there are lots of import choices for Permission. Please select androidx.well being.join.shopper.permission
.
Right here’s what’s occurring in checkPermissionsAndRun
:
- You initially come up with a
HealthConnectClient
object.getOrCreate
creates a brand new occasion or returns an current one if it’s accessible. - Create a set of permissions with required knowledge varieties to request permissions inside your utility. Permissions in these units must be declared within the health_permissions useful resource array.
- Create a request permission launcher. On launch, customers might be prompted for permissions declared within the health_permissions useful resource array.
- Lastly, by way of
HealthConnectClient
, you test whether or not you’ve the required permissions. If permissions aren’t accessible, you request permissions by way ofrequestPermissions
launcher.
onPermissionAvailable
known as when you’ve all required permissions. At this level, it’s potential to learn or write knowledge.
Add the next after the closing utility
tag inside AndroidManifest.xml:
<queries>
<package deal android:title="com.google.android.apps.healthdata" />
</queries>
This checks whether or not Well being Join APK is put in.
Lastly, inside onCreate
in MainActivity.kt, exchange // Your code
with the next code:
if (HealthConnectClient.isAvailable(this)) {
// Well being Join is obtainable
checkPermissionsAndRun()
} else {
Toast.makeText(
this, "Well being Join is just not accessible", Toast.LENGTH_SHORT
).present()
}
Right here’s what’s occurring:
- Via
HealthConnectClient
, you test whether or not Well being Join is obtainable. - Whether it is accessible, you test 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 strive by working 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(
depend = 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 report the info in a small interval. This fashion you’ll be able to insert the info a number of instances in a day.
- Adopted by one other listing that accommodates
StepsRecord
andTotalCaloriesBurnedRecord
data. - Then lastly, you insert the created report by way of the
HealthConnectClient
occasion.recordUidsList
accommodates 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 you want to do to jot down knowledge by way of the Well being Join API. Run the venture, enter values and faucet the button.
Studying Knowledge
You’ll be able to learn knowledge in two methods utilizing HealthConnectClient.
-
ReadRecordsRequest
: Learn data decided by time vary and different filters. You’ll use this methodology to learn the each day steps depend and energy consumption. -
AggregateRequest
: Learn aggregations for a givenAggregateMetric
. You’ll use this methodology to learn month-to-month step counts and caloric intakes.
Studying Knowledge by way of a ReadRecordsRequest
In MainActivity.kt, add the next after insertData()
:
personal droop enjoyable readDailyRecords(shopper: HealthConnectClient) {
// 1
val at the moment = ZonedDateTime.now()
val startOfDay = at the moment.truncatedTo(ChronoUnit.DAYS)
val timeRangeFilter = TimeRangeFilter.between(
startOfDay.toLocalDateTime(),
at the moment.toLocalDateTime()
)
// 2
val stepsRecordRequest = ReadRecordsRequest(StepsRecord::class, timeRangeFilter)
val numberOfStepsToday = shopper.readRecords(stepsRecordRequest)
.data
.sumOf { it.depend }
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
. Via theHealthConnectClient
occasion, you learn data and get the sum. You get the sum as a result of there could be many data for steps taken at the moment. Lastly, you show the each day steps depend. - This is similar as Step 2, however the
ReadRecordsRequest
is forTotalCaloriesBurnedRecord
.
Studying Knowledge by way of an AggregateRequest
Add the next methodology on the backside of MainActivity:
personal droop enjoyable readAggregatedData(shopper: HealthConnectClient) {
// 1
val at the moment = ZonedDateTime.now()
val startOfDayOfThisMonth = at the moment.withDayOfMonth(1)
.truncatedTo(ChronoUnit.DAYS)
val elapsedDaysInMonth = Period.between(startOfDayOfThisMonth, at the moment)
.toDays() + 1
val timeRangeFilter = TimeRangeFilter.between(
startOfDayOfThisMonth.toInstant(),
at the moment.toInstant()
)
// 2
val knowledge = shopper.mixture(
AggregateRequest(
metrics = setOf(
StepsRecord.COUNT_TOTAL,
TotalCaloriesBurnedRecord.ENERGY_TOTAL
),
timeRangeFilter = timeRangeFilter,
)
)
// 3
val steps = knowledge[StepsRecord.COUNT_TOTAL] ?: 0
val averageSteps = steps / elapsedDaysInMonth
val stepsAverageTextView = findViewById<TextView>(R.id.stepsAverageValue)
stepsAverageTextView.textual content = averageSteps.toString()
// 4
val caloriesBurned = knowledge[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)
}
Word: Whereas importing dependencies, there are lots of 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’ll be able to calculate the typical. - You’re making an
mixture
request by way ofHealthConnectClient
with a set of measurements to get the full steps and energy inside a particular time vary. The good thing about aggregated knowledge is it contains primary aggregations or aggregating knowledge into buckets. - You’re calculating
averageSteps
and updating the format. - You’re calculating
averageCaloriesBurned
and updating the format. For a greater UI, you’re rounding the calorie values as much as two decimals.
Add the next within the strings.xml file.
<string title="format_calories_average">%.2f</string>
You’re nearly there. You now have features that learn knowledge, however you want to join a couple of ultimate dots.
Add one other methodology 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 knowledge.
Now, inside onPermissionAvailable
, exchange // todo: learn knowledge
with the next.
readData(shopper)
By doing so, you’ll be able to learn the info and replace the format as quickly as you’ve permissions accessible.
Lastly, add the next on the finish of the lifecycleScope.launch {
block, inside insertData
:
readData(shopper)
This may make sure you present up to date knowledge after a person inserts new knowledge.
Construct and Run
You’re achieved! Construct and run the app to see the outcome. Now you can write knowledge and likewise see your current knowledge.
The place to Go From Right here?
Congratulations! You’ve realized about Well being Join by making a easy app. Now you’ve 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 venture.
You’ll be able to take a couple of steps to enhance your app: