Synchronizuj dane

Ten przewodnik jest zgodny z Health Connect w wersji 1.1.0-alpha12.

Większość aplikacji zintegrowanych z Health Connect ma własny magazyn danych, który jest źródłem wiarygodnych informacji. Health Connect udostępnia sposoby synchronizowania aplikacji.

W zależności od architektury aplikacji proces synchronizacji może obejmować niektóre lub wszystkie z tych działań:

  • Przesyłanie nowych lub zaktualizowanych danych z magazynu danych aplikacji do Health Connect.
  • Pobieranie zmian danych z Health Connect do magazynu danych aplikacji.
  • Usuwanie danych z Health Connect, gdy zostaną usunięte z magazynu danych aplikacji.

W każdym przypadku upewnij się, że proces synchronizacji utrzymuje spójność Health Connect i magazynu danych aplikacji.

Przesyłanie danych do Health Connect

Pierwszym etapem procesu synchronizacji jest przesłanie danych z magazynu danych aplikacji do magazynu danych Health Connect.

Przygotowywanie danych

Zazwyczaj rekordy w magazynie danych aplikacji zawierają te informacje:

  • Unikalny klucz, np. UUID.
  • Wersja lub sygnatura czasowa.

Podczas synchronizowania danych z Health Connect identyfikuj i przesyłaj tylko te dane, które zostały wstawione, zaktualizowane lub usunięte od czasu ostatniej synchronizacji.

Zapisywanie danych w Health Connect

Aby przesłać dane do Health Connect:

  1. Pobierz listę nowych, zaktualizowanych lub usuniętych wpisów z magazynu danych aplikacji.
  2. W przypadku każdego wpisu utwórz obiekt Record odpowiedni dla danego typu danych. Na przykład w przypadku danych związanych z wagą utwórz obiekt WeightRecord.
  3. Określ obiekt Metadata dla każdego obiektu Record. Obejmuje to clientRecordId, czyli identyfikator z magazynu danych aplikacji, którego możesz użyć do jednoznacznego zidentyfikowania rekordu. Możesz użyć istniejącego unikalnego klucza. Jeśli dane są wersjonowane, podaj też clientRecordVersion, który jest zgodny z wersjonowaniem używanym w danych. Jeśli nie są wersjonowane, możesz użyć wartości Long bieżącej sygnatury czasowej.

    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. Zaktualizuj dane w Health Connect za pomocą insertRecords. Aktualizowanie danych oznacza, że wszystkie istniejące dane w Health Connect zostaną zastąpione, o ile wartości clientRecordId znajdują się w magazynie danych Health Connect, a clientRecordVersion jest wyższa niż istniejąca wartość. W przeciwnym razie zaktualizowane dane zostaną zapisane jako nowe dane.

    healthConnectClient.insertRecords(arrayListOf(record))

Aby dowiedzieć się więcej o praktycznych aspektach przesyłania danych, zapoznaj się ze sprawdzonymi metodami dotyczącymi zapisywania danych.

Przechowywanie identyfikatorów Health Connect

Jeśli Twoja aplikacja odczytuje też dane z Health Connect, po zaktualizowaniu rekordów zapisz ich identyfikator id z Health Connect. Ten identyfikator id jest potrzebny do przetwarzania usunięć, gdy pobierasz zmiany danych z Health Connect.

Funkcja insertRecords zwraca InsertRecordsResponse, który zawiera listę wartości id. Użyj odpowiedzi, aby pobrać identyfikatory rekordów i je zapisać.

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

Pobieranie danych z Health Connect

Drugim etapem procesu synchronizacji jest pobranie zmian danych z Health Connect do magazynu danych aplikacji. Zmiany danych mogą obejmować aktualizacje i usunięcia.

Pobieranie tokena zmian

Aby pobrać listę zmian z Health Connect, aplikacja musi śledzić tokeny Changes. Możesz ich używać podczas wysyłania prośby o Changes, aby zwracać zarówno listę zmian danych, jak i nowy token Changes do użycia przy następnym razem.

Aby uzyskać token Changes, wywołaj getChangesToken i podaj wymagane typy danych.

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

Sprawdzanie zmian danych

Gdy uzyskasz token Changes, użyj go, aby pobrać wszystkie Changes. Zalecamy utworzenie pętli, która będzie sprawdzać, czy są dostępne zmiany danych. Oto kolejne kroki:

  1. Wywołaj getChanges za pomocą tokena, aby uzyskać listę Changes.
  2. Sprawdź, czy typ zmiany to an UpsertionChange or a DeletionChange, and perform the necessary operations.
    • W przypadku UpsertionChange uwzględniaj tylko zmiany, które nie pochodzą z wywołującej aplikacji, aby uniknąć ponownego importowania danych.
  3. Przypisz następny token Changes jako nowy token.
  4. Powtarzaj kroki 1–3, aż nie będzie już żadnych Changes.
  5. Zapisz następny token i zarezerwuj go na przyszły import.

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
}

Aby dowiedzieć się więcej o praktycznych aspektach pobierania danych, zapoznaj się ze sprawdzonymi metodami dotyczącymi synchronizowania danych.

Przetwarzanie zmian danych

Wprowadź zmiany w magazynie danych aplikacji. W przypadku UpsertionChange użyj id i lastModifiedTime z jego metadata, aby zaktualizować rekord. W przypadku DeletionChange użyj podanego identyfikatora id, aby usunąć rekord. Wymaga to zapisania rekordu id, jak opisano w sekcji Przechowywanie identyfikatorów Health Connect.

Usuwanie danych z Health Connect

Gdy użytkownik usunie swoje dane z Twojej aplikacji, upewnij się, że dane zostaną też usunięte z Health Connect. Aby to zrobić, użyj deleteRecords. Ta funkcja przyjmuje typ rekordu oraz listę wartości id i clientRecordId, co ułatwia zbiorcze usuwanie wielu danych. Dostępna jest też alternatywna deleteRecords, która przyjmuje timeRangeFilter.

Synchronizacja z urządzeń do noszenia z niskim opóźnieniem

Aby synchronizować dane z urządzenia do noszenia z Health Connect z niskim opóźnieniem, użyj CompanionDeviceService. To podejście działa w przypadku urządzeń, które obsługują powiadomienia lub wskazania BLE GATT i są przeznaczone na Androida 8.0 (poziom interfejsu API 26) lub nowszego. CompanionDeviceService umożliwia aplikacji odbieranie danych z urządzeń do noszenia i zapisywanie ich w Health Connect, nawet gdy aplikacja nie jest jeszcze uruchomiona. Więcej informacji o sprawdzonych metodach dotyczących BLE znajdziesz w artykule Bluetooth Low Energy – omówienie.

Łączenie urządzenia

Najpierw aplikacja musi przeprowadzić użytkownika przez jednorazowy proces łączenia urządzenia do noszenia z aplikacją za pomocą CompanionDeviceManager. Dzięki temu aplikacja uzyskuje uprawnienia niezbędne do interakcji z urządzeniem. Więcej informacji znajdziesz w artykule Parowanie urządzeń towarzyszących.

Deklarowanie usługi w pliku manifestu

Następnie zadeklaruj CompanionDeviceService w pliku manifestu aplikacji. Dodaj do pliku AndroidManifest.xml te informacje:

<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>

Tworzenie CompanionDeviceService

Na koniec utwórz klasę, która rozszerza CompanionDeviceService. Ta usługa obsługuje połączenie z urządzeniem do noszenia i odbiera dane za pomocą wywołań zwrotnych BLE GATT. Gdy zostaną odebrane nowe dane, są one natychmiast zapisywane w Health Connect.

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()
        }
    }
}

Sprawdzone metody synchronizowania danych

Na proces synchronizacji wpływają te czynniki.

Wygaśnięcie tokenu

Nieużywany token Changes wygasa w ciągu 30 dni, dlatego musisz użyć strategii synchronizacji, która pozwoli uniknąć utraty informacji w takim przypadku. Twoja strategia może obejmować te podejścia:

  • Wyszukaj w magazynie danych aplikacji ostatnio używany rekord, który ma też identyfikator id z Health Connect.
  • Poproś o rekordy z Health Connect, które zaczynają się od określonej sygnatury czasowej, a następnie wstaw je lub zaktualizuj w magazynie danych aplikacji.
  • Poproś o token zmian, aby zarezerwować go na następny raz.

Zalecane strategie zarządzania zmianami

Jeśli Twoja aplikacja otrzymuje nieprawidłowe lub wygasłe tokeny Changes, zalecamy te strategie zarządzania w zależności od jej zastosowania w logice:

  • Odczytywanie i usuwanie duplikatów wszystkich danych. Jest to najbardziej optymalna strategia.
    • Zapisz sygnaturę czasową ostatniego odczytu danych z Health Connect.
    • Po wygaśnięciu tokena ponownie odczytaj wszystkie dane od najnowszej sygnatury czasowej lub z ostatnich 30 dni. Następnie usuń duplikaty w porównaniu z wcześniej odczytanymi danymi za pomocą identyfikatorów.
    • Najlepiej zaimplementuj identyfikatory klientów, ponieważ są one wymagane do aktualizacji danych.
  • Odczytuj tylko dane od czasu ostatniej sygnatury czasowej odczytu. Powoduje to pewne rozbieżności w danych w czasie wygaśnięcia tokena zmian, ale okres ten jest krótszy i może trwać od kilku godzin do kilku dni.
    • Zapisz sygnaturę czasową ostatniego odczytu danych z Health Connect.
    • Po wygaśnięciu tokena odczytaj wszystkie dane od tej sygnatury czasowej.
  • Usuń, a następnie odczytaj dane z ostatnich 30 dni. Jest to bardziej zgodne z tym, co dzieje się podczas pierwszej integracji.
    • Usuń wszystkie dane odczytane przez aplikację z Health Connect w ciągu ostatnich 30 dni.
    • Po usunięciu ponownie odczytaj wszystkie te dane.
  • Odczytuj dane z ostatnich 30 dni bez usuwania duplikatów. Jest to najmniej optymalna strategia, która powoduje wyświetlanie użytkownikom zduplikowanych danych.
    • Usuń wszystkie dane odczytane przez aplikację z Health Connect w ciągu ostatnich 30 dni.
    • Zezwól na duplikaty wpisów.

Tokeny zmian typu danych

Jeśli Twoja aplikacja używa niezależnie więcej niż 1 typu danych, użyj osobnych tokenów zmian dla każdego typu danych. Używaj listy wielu typów danych z interfejsem Changes Sync API tylko wtedy, gdy te typy danych są używane razem lub wcale.

Odczytywanie na pierwszym planie

Aplikacje mogą odczytywać dane z Health Connect tylko wtedy, gdy działają na pierwszym planie. Podczas synchronizowania danych z Health Connect dostęp do tej usługi może zostać w dowolnym momencie przerwany. Na przykład aplikacja musi obsługiwać przerwy w trakcie synchronizacji podczas odczytywania dużej ilości danych z Health Connect i kontynuować działanie po następnym otwarciu.

Odczytywanie w tle

Możesz poprosić o uruchomienie aplikacji w tle i odczytywanie danych z Health Connect. Jeśli poprosisz o uprawnienie Background Read, użytkownik może przyznać aplikacji dostęp do odczytywania danych w tle.

Czasy importu

Ponieważ aplikacja nie może otrzymywać powiadomień o nowych danych, sprawdzaj, czy są nowe dane, w 2 miejscach:

  • Za każdym razem, gdy aplikacja staje się aktywna na pierwszym planie. W takim przypadku użyj zdarzeń cyklu życia.
  • Okresowo, gdy aplikacja pozostaje na pierwszym planie. Powiadamiaj użytkowników o dostępności nowych danych, aby mogli zaktualizować ekran i odzwierciedlić zmiany.