Sincronizza dati

Questa guida è compatibile con Health Connect versione 1.1.0-alpha12 o successive.

La maggior parte delle app che si integrano con Health Connect ha un proprio datastore che funge da fonte attendibile. Health Connect offre diversi modi per mantenere sincronizzata la tua app.

A seconda dell'architettura della tua app, il processo di sincronizzazione potrebbe comportare alcune o tutte le seguenti azioni:

  • Inserisci dati nuovi o aggiornati dal datastore della tua app in Connessione Salute.
  • Estrai le modifiche ai dati da Health Connect nel datastore della tua app.
  • Elimina i dati da Health Connect quando vengono eliminati nell'archivio dati della tua app.

In ogni caso, assicurati che il processo di sincronizzazione mantenga allineati sia Health Connect sia l'archivio dati della tua app.

Inserisci i dati in Health Connect

La prima parte del processo di sincronizzazione consiste nell'inserire i dati dal datastore dell'app al datastore di Health Connect.

Preparare i dati

In genere, i record nel datastore dell'app contengono i seguenti dettagli:

  • Una chiave univoca, ad esempio UUID.
  • Una versione o un timestamp.

Durante la sincronizzazione dei dati con Health Connect, identifica e fornisci solo i dati che sono stati inseriti, aggiornati o eliminati dall'ultima sincronizzazione.

Scrivere dati su Health Connect

Per inserire i dati in Connessione Salute, segui questi passaggi:

  1. Ottenere un elenco di voci nuove, aggiornate o eliminate dal datastore dell'app.
  2. Per ogni voce, crea un oggetto Record appropriato per quel tipo di dati. Ad esempio, crea un oggetto WeightRecord per i dati relativi al peso.
  3. Specifica un oggetto Metadata con ogni Record. Sono inclusi clientRecordId, ovvero un ID del datastore della tua app che puoi utilizzare per identificare in modo univoco il record. A questo scopo, puoi utilizzare la chiave univoca esistente. Se i tuoi dati sono sottoposti a controllo di versione, fornisci anche un clientRecordVersion che sia in linea con il controllo di versione utilizzato nei tuoi dati. Se non è presente una versione, puoi utilizzare il valore Long del timestamp corrente come alternativa.

    val recordVersion = 0L
    // Specify as needed
    // The clientRecordId is an ID that you choose for your record. This
    // is often the same ID you use in your app's datastore.
    val clientRecordId = "<your-record-id>"
    
    val record = WeightRecord(
        metadata = Metadata.activelyRecorded(
            clientRecordId = clientRecordId,
            clientRecordVersion = recordVersion,
            device = Device(type = Device.TYPE_SCALE)
        ),
        weight = Mass.kilograms(62.0),
        time = Instant.now(),
        zoneOffset = ZoneOffset.UTC,
    )
    healthConnectClient.insertRecords(listOf(record))

  4. Applica l'upsert dei dati a Health Connect utilizzando insertRecords. L'upsert dei dati comporta la sovrascrittura di tutti i dati esistenti in Health Connect, a condizione che i valori clientRecordId esistano nel datastore di Health Connect e che clientRecordVersion sia superiore al valore esistente. In caso contrario, i dati sottoposti a upsert vengono scritti come nuovi dati.

    healthConnectClient.insertRecords(arrayListOf(record))

Per scoprire le considerazioni pratiche per l'inserimento dei dati, consulta le best practice per Scrivi dati.

Memorizza gli ID di Health Connect

Se la tua app legge anche i dati da Health Connect, memorizza l'id di Health Connect per i record dopo aver applicato l'upsert. Questo id è necessario per elaborare le eliminazioni quando estrai le modifiche ai dati da Health Connect.

La funzione insertRecords restituisce un InsertRecordsResponse che contiene l'elenco dei valori id. Utilizza la risposta per ottenere gli ID record e memorizzarli.

val response = healthConnectClient.insertRecords(listOf(record))
for (recordId in response.recordIdsList) {
    // Store recordId to your app's datastore
}

Estrai i dati da Connessione Salute

La seconda parte del processo di sincronizzazione consiste nel recuperare eventuali modifiche ai dati da Health Connect al datastore della tua app. Le modifiche ai dati possono includere aggiornamenti ed eliminazioni.

Ottieni un token Changes

Per ottenere un elenco delle modifiche da estrarre da Health Connect, la tua app deve tenere traccia dei token Changes. Puoi utilizzarli quando richiedi Modifiche per restituire sia un elenco di modifiche ai dati sia un nuovo token Modifiche da utilizzare la volta successiva.

Per ottenere un token Changes, chiama getChangesToken e fornisci i tipi di dati richiesti.

val changesToken = healthConnectClient.getChangesToken(
    ChangesTokenRequest(recordTypes = setOf(WeightRecord::class))
)

Verifica se sono state apportate modifiche ai dati

Ora che hai ottenuto un token Changes, utilizzalo per recuperare tutte le modifiche. Ti consigliamo di creare un loop per esaminare tutte le modifiche in cui viene verificato se sono presenti modifiche ai dati disponibili. Ecco i passaggi successivi:

  1. Chiama getChanges utilizzando il token per ottenere un elenco di modifiche.
  2. Controlla ogni modifica per verificare se il tipo di modifica è un UpsertionChange o un DeletionChange ed esegui le operazioni necessarie.
    • Per UpsertionChange, accetta solo le modifiche che non provengono dall'app di chiamate per assicurarti di non reimportare i dati.
  3. Assegna il token Changes successivo come nuovo token.
  4. Ripeti i passaggi 1-3 finché non rimangono più Modifiche.
  5. Memorizza il token successivo e riservalo per un'importazione futura.

suspend fun processChanges(context: Context, token: String): String {
    var nextChangesToken = token
    do {
        val response = healthConnectClient.getChanges(nextChangesToken)
        response.changes.forEach { change ->
            when (change) {
                is UpsertionChange ->
                    if (change.record.metadata.dataOrigin.packageName != context.packageName) {
                        processUpsertionChange(change)
                    }
                is DeletionChange -> processDeletionChange(change)
            }
        }
        nextChangesToken = response.nextChangesToken
    } while (response.hasMore)
    // Return and store the changes token for use next time.
    return nextChangesToken
}

Per scoprire le considerazioni pratiche per l'estrazione dei dati, consulta le best practice per i dati di sincronizzazione.

Modifiche al trattamento dei dati

Riflettere le modifiche nel datastore dell'app. Per UpsertionChange, utilizza id e lastModifiedTime dal relativo metadata per applicare l'upsert al record. Per DeletionChange, utilizza il id fornito per eliminare il record. Per farlo, devi aver archiviato il record id come indicato in Archivia gli ID Health Connect.

Elimina i dati da Connessione Salute

Quando un utente elimina i propri dati dalla tua app, assicurati che vengano rimossi anche da Connessione Salute. A questo scopo, usa deleteRecords. Questo metodo accetta un tipo di record e un elenco di valori id e clientRecordId, il che semplifica l'eliminazione di più dati in batch. È disponibile anche un'alternativa deleteRecords che accetta un timeRangeFilter.

Sincronizzazione a bassa latenza dai dispositivi indossabili

Per sincronizzare i dati di un dispositivo fitness indossabile con Health Connect con una latenza ridotta, utilizza CompanionDeviceService. Questo approccio funziona per i dispositivi che supportano le notifiche o le indicazioni BLE GATT e che hanno come target Android 8.0 (livello API 26) o versioni successive. CompanionDeviceService consente alla tua app di ricevere dati dai dispositivi indossabili e di scriverli in Health Connect, anche quando l'app non è già in esecuzione. Per maggiori dettagli sulle best practice per BLE, consulta la panoramica di Bluetooth Low Energy.

Associa il dispositivo

Innanzitutto, l'app deve guidare l'utente attraverso una procedura una tantum per associare il wearable all'app utilizzando CompanionDeviceManager. In questo modo, l'app riceve le autorizzazioni necessarie per interagire con il dispositivo. Per ulteriori informazioni, consulta Accoppiamento di dispositivi complementari.

Dichiara il servizio nel manifest

Successivamente, dichiara CompanionDeviceService nel file manifest dell'app. Aggiungi quanto segue al tuo AndroidManifest.xml:

<manifest ...>
   <application ...>
       <service
           android:name=".MyWearableService"
           android:exported="true"
           android:permission="android.permission.BIND_COMPANION_DEVICE_SERVICE">
           <intent-filter>
               <action android:name="android.companion.CompanionDeviceService" />
           </intent-filter>
       </service>
   </application>
</manifest>

Crea CompanionDeviceService

Infine, crea una classe che estende CompanionDeviceService. Questo servizio gestisce la connessione al dispositivo indossabile e riceve i dati tramite callback BLE GATT. Quando vengono ricevuti nuovi dati, vengono scritti immediatamente in Connessione Salute.

private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private var healthConnectClient: HealthConnectClient? = null
private var bluetoothGatt: BluetoothGatt? = null

override fun onDeviceAppeared(address: String) {
    super.onDeviceAppeared(address)
    healthConnectClient = HealthConnectClient.getOrCreate(this)

    serviceScope.launch {
        val granted = healthConnectClient?.permissionController?.getGrantedPermissions()

        // 1. Check permissions ONCE when the device connects
        if (granted?.contains(HealthPermission.getWritePermission(HeartRateRecord::class)) ?: false) {
            // This is where you'd actually start the Bluetooth connection
            // bluetoothGatt = gattCallback.connect(...)
        }

        // 2. Do your initial database read
        readExerciseSessionAndRoute()
    }
}

private val gattCallback = object : BluetoothGattCallback() {
    override fun onCharacteristicChanged(
        gatt: BluetoothGatt,
        characteristic: BluetoothGattCharacteristic,
        value: ByteArray
    ) {
        super.onCharacteristicChanged(gatt, characteristic, value)

        // 3. ONLY process the incoming data here
        val rawData = value

        serviceScope.launch {
            // parseWearableData(rawData)
            // insertExerciseRoute() or writeToHealthConnect()
        }
    }
}

Best practice per la sincronizzazione dei dati

I seguenti fattori influiscono sul processo di sincronizzazione.

Scadenza dei token

Poiché un token Changes non utilizzato scade entro 30 giorni, devi utilizzare una strategia di sincronizzazione che eviti la perdita di informazioni in questo caso. La tua strategia potrebbe includere i seguenti approcci:

  • Cerca nel datastore dell'app il record utilizzato più di recente che ha anche un id da Health Connect.
  • Richiedi i record da Health Connect che iniziano con un timestamp specifico, quindi inseriscili o aggiornali nel datastore della tua app.
  • Richiedi un token Changes per riservarlo per la prossima volta che sarà necessario.

Strategie di gestione delle modifiche consigliate

Se la tua app riceve token Changes non validi o scaduti, ti consigliamo le seguenti strategie di gestione a seconda della sua applicazione nella tua logica:

  • Leggi e deduplica tutti i dati. Questa è la strategia ideale.
    • Memorizza il timestamp dell'ultima volta che ha letto i dati da Health Connect.
    • Alla scadenza del token, rileggi tutti i dati dal timestamp più recente o degli ultimi 30 giorni. Poi, deduplica i dati rispetto a quelli letti in precedenza utilizzando gli identificatori.
    • Idealmente, implementa gli ID client, poiché sono necessari per gli aggiornamenti dei dati.
  • Leggi solo i dati dal timestamp dell'ultima lettura. Ciò comporta alcune discrepanze nei dati nel periodo di scadenza del token Changes, ma il periodo di tempo è più breve e potrebbe richiedere da poche ore a un paio di giorni.
    • Memorizza il timestamp dell'ultima volta che hanno letto i dati da Health Connect.
    • Alla scadenza del token, leggi tutti i dati a partire da questo timestamp.
  • Elimina e poi leggi i dati degli ultimi 30 giorni. Questo approccio è più in linea con quanto accade durante la prima integrazione.
    • Elimina tutti i dati letti dall'app da Health Connect negli ultimi 30 giorni.
    • Una volta eliminati, leggi di nuovo tutti questi dati.
  • Leggi i dati degli ultimi 30 giorni senza deduplicazione. Questa è la strategia meno ideale e comporta la visualizzazione di dati duplicati per gli utenti.
    • Elimina tutti i dati letti dall'app da Health Connect negli ultimi 30 giorni.
    • Consenti voci duplicate.

Token di modifica del tipo di dati

Se la tua app utilizza più di un tipo di dati in modo indipendente, utilizza token di modifica separati per ogni tipo di dati. Utilizza un elenco di più tipi di dati con l'API Changes Sync solo se questi tipi di dati vengono utilizzati insieme o non vengono utilizzati affatto.

Letture in primo piano

Le app possono leggere i dati da Health Connect solo quando sono in primo piano. Durante la sincronizzazione dei dati da Health Connect, l'accesso a Health Connect potrebbe essere interrotto in qualsiasi momento. Ad esempio, l'app deve gestire le interruzioni durante la sincronizzazione quando legge una grande quantità di dati da Health Connect e continuare alla successiva apertura dell'app.

Letture in background

Puoi richiedere che la tua applicazione venga eseguita in background e legga i dati da Health Connect. Se richiedi l'autorizzazione Background Read, l'utente può concedere alla tua app l'accesso per leggere i dati in background.

Tempi di importazione

Poiché la tua app non può ricevere notifiche di nuovi dati, controlla la presenza di nuovi dati in due punti:

  • Ogni volta che l'app diventa attiva in primo piano. In questo caso, utilizza gli eventi del ciclo di vita.
  • Periodicamente, mentre l'app rimane in primo piano. Invia una notifica agli utenti quando sono disponibili nuovi dati, consentendo loro di aggiornare lo schermo per riflettere le modifiche.