Sincronizza dati

Questa guida è compatibile con la versione 1.1.0-alpha12 di Health Connect.

La maggior parte delle app che si integrano con Health Connect hanno un proprio archivio dati che funge da fonte di verità. Health Connect offre modi per mantenere sincronizzata la tua app.

A seconda dell'architettura dell'app, la procedura di sincronizzazione potrebbe comportare alcune o tutte le seguenti azioni:

  • Inserire dati nuovi o aggiornati dall'archivio dati dell'app in Health Connect.
  • Estrarre le modifiche dei dati da Health Connect nell'archivio dati dell'app.
  • Eliminare i dati da Health Connect quando vengono eliminati nell'archivio dati dell'app.

In ogni caso, assicurati che la procedura di sincronizzazione mantenga allineati sia Health Connect sia l'archivio dati dell'app.

Inserire dati in Health Connect

La prima parte della procedura di sincronizzazione consiste nell'inserire i dati dall'archivio dati dell'app nell'archivio dati di Health Connect.

Preparare i dati

In genere, i record nell'archivio dati dell'app hanno i seguenti dettagli:

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

Quando sincronizzi i dati con Health Connect, identifica e inserisci solo i dati che sono stati inseriti, aggiornati o eliminati dall'ultima sincronizzazione.

Scrivere dati in Health Connect

Per inserire i dati in Health Connect:

  1. Ottieni un elenco di voci nuove, aggiornate o eliminate dall'archivio dati 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. È incluso clientRecordId, un ID dell'archivio dati dell'app che puoi utilizzare per identificare in modo univoco il record. Puoi utilizzare la chiave univoca esistente per questo scopo. Se i dati sono versionati, fornisci anche un clientRecordVersion che sia in linea con il versionamento utilizzato nei dati. Se non sono versionati, puoi utilizzare come alternativa il valore Long del timestamp corrente.

    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(
            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. Esegui l'upsert dei dati in Health Connect utilizzando insertRecords. L'upsert dei dati significa che tutti i dati esistenti in Health Connect vengono sovrascritti purché i valori clientRecordId esistano nell'archivio dati di Health Connect e clientRecordVersion sia superiore al valore esistente. In caso contrario, i dati di cui è stato eseguito l'upsert vengono scritti come nuovi dati.

    healthConnectClient.insertRecords(arrayListOf(record))

Per scoprire le considerazioni pratiche relative all'inserimento dei dati, consulta le best practice per la scrittura dei dati.

Memorizzare 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 eseguito l'upsert. Questo id è necessario per elaborare le eliminazioni quando estrai le modifiche dei dati da Health Connect.

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

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

Estrarre dati da Health Connect

La seconda parte della procedura di sincronizzazione consiste nell'estrarre le modifiche dei dati da Health Connect nell'archivio dati dell'app. Le modifiche dei dati possono includere aggiornamenti ed eliminazioni.

Ottenere un token di modifiche

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

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

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

Exception

Verificare la presenza di modifiche dei dati

Ora che hai ottenuto un token Modifiche, utilizzalo per ottenere tutte le Modifiche. Ti consigliamo di creare un loop per esaminare tutte le Modifiche in cui viene verificata la presenza di modifiche dei dati disponibili. Ecco i passaggi da seguire:

  1. Chiama getChanges utilizzando il token per ottenere un elenco di Modifiche.
  2. Verifica se il tipo di modifica è un UpsertionChange o un DeletionChange ed esegui le operazioni necessarie.
    • Per UpsertionChange, prendi in considerazione solo le modifiche che non provengono dall'app chiamante per assicurarti di non reimportare i dati.
  3. Assegna il token Modifiche successivo come nuovo token.
  4. Ripeti i passaggi da 1 a 3 finché non rimangono 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 relative all'estrazione dei dati, consulta le best practice per la sincronizzazione dei dati.

Elaborare le modifiche dei dati

Rifletti le modifiche nell'archivio dati dell'app. Per UpsertionChange, utilizza id e lastModifiedTime dei relativi metadata per eseguire l'upsert del record. Per DeletionChange, utilizza il id fornito per eliminare il record. Per farlo, devi aver memorizzato il record id come indicato in Memorizzare gli ID di Health Connect.

Eliminare dati da Health Connect

Quando un utente elimina i propri dati dalla tua app, assicurati che vengano anche rimossi da Health Connect. Utilizza deleteRecords per farlo. Questa funzione accetta un tipo di record e un elenco di valori id e clientRecordId, il che la rende comoda per eliminare in batch più dati. È disponibile anche una funzione alternativa deleteRecords che accetta un timeRangeFilter.

Sincronizzazione a bassa latenza dai wearable

Per sincronizzare i dati da un dispositivo per il fitness indossabile a Health Connect con una bassa latenza, 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 dagli indossabili e di scriverli in Health Connect, anche quando l'app non è già in esecuzione. Per ulteriori dettagli sulle best practice BLE, consulta la panoramica su Bluetooth Low Energy.

Associare il dispositivo

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

Dichiarare il servizio nel file manifest

Dopodiché, dichiara CompanionDeviceService nel file manifest dell'app. Aggiungi quanto segue a 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>

Creare CompanionDeviceService

Infine, crea una classe che estenda CompanionDeviceService. Questo servizio gestisce la connessione al dispositivo indossabile e riceve i dati tramite i 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 sulla procedura di sincronizzazione.

Scadenza del token

Poiché un token Modifiche inutilizzato 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 abbia anche un id di Health Connect.
  • Richiedi i record da Health Connect che iniziano con un timestamp specifico, quindi inseriscili o aggiornali nell'archivio dati dell'app.
  • Richiedi un token Modifiche per riservarlo per la volta successiva in cui è necessario.

Strategie consigliate per la gestione delle modifiche

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

  • Leggi ed elimina i duplicati di tutti i dati. Questa è la strategia più ideale.
    • Memorizza il timestamp dell'ultima volta che hai letto i dati da Health Connect.
    • Alla scadenza del token, rileggi tutti i dati dal timestamp più recente o degli ultimi 30 giorni. Quindi, elimina i duplicati rispetto ai dati letti in precedenza utilizzando gli identificatori.
    • Idealmente, implementa gli ID client, poiché sono obbligatori per gli aggiornamenti dei dati.
  • Leggi solo i dati dal timestamp dell'ultima lettura. In questo modo si verificano alcune discrepanze dei dati intorno al momento della scadenza del token Modifiche, 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 hai 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. Questa strategia è più in linea con ciò che 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 eliminare i duplicati. Questa è la strategia meno ideale e comporta la visualizzazione di dati duplicati agli utenti.
    • Elimina tutti i dati letti dall'app da Health Connect negli ultimi 30 giorni.
    • Consenti le voci duplicate.

Token Modifiche per tipo di dati

Se la tua app utilizza più tipi di dati in modo indipendente, utilizza token Modifiche separati per ogni tipo di dati. Utilizza un elenco di più tipi di dati con l'API Sincronizzazione modifiche 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. Quando sincronizzi i dati da Health Connect, l'accesso a Health Connect potrebbe essere interrotto in qualsiasi momento. Ad esempio, la tua app deve gestire le interruzioni a metà di una sincronizzazione quando legge una grande quantità di dati da Health Connect e continuare la volta successiva che l'app viene aperta.

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 relative a nuovi dati, controlla la presenza di nuovi dati in due punti:

  • Ogni volta che la tua 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.