Develop

Users sample overview

Updated: May 7, 2026

Overview

This sample demonstrates how to retrieve user profile information and access tokens using the Horizon Platform SDK Users API. It shows the MVVM pattern with Jetpack Compose, coroutine-based API calls, and centralized error handling for platform SDK integration.

What you will learn

  • Initialize the Horizon Platform SDK service connection in an Android app
  • Retrieve user profile data by user ID using the Users API
  • Fetch access tokens for authenticated requests
  • Implement MVVM architecture with StateFlow for SDK-driven UI updates
  • Handle asynchronous SDK operations with Kotlin coroutines and centralized error handling

Requirements

  • Target device: Meta Quest device with Developer Mode enabled
  • Development environment: Android Studio
  • Platform SDK setup: Obtain a Horizon Platform app ID from the Meta Developer Portal
For detailed build prerequisites and SDK version requirements, see the sample README.

Get started

Clone the horizon-platform-sdk-samples repository and open the users/ directory in Android Studio. Before running, replace the APPLICATION_ID in MainActivity.kt with your app ID from the Meta Developer Portal. Connect your Quest device via USB, build the project, and deploy to the device. For complete setup instructions including SDK installation and developer mode configuration, see the Platform SDK setup guide.

Explore the sample

The sample uses MVVM architecture with two primary source files:
FileWhat it demonstratesKey concepts
MainActivity.kt
SDK initialization and Compose UI
HorizonServiceConnection.connect(), state observation with collectAsStateWithLifecycle(), user input handling
UsersViewModel.kt
Business logic and state management
Users API instantiation, coroutine-based API calls, centralized error handling with executeAction(), immutable state updates with StateFlow; includes UsersUiState data class for UI state modeling

Runtime behavior

When you run this sample, you see a simple form with two action buttons. Enter a user ID in the text field and tap Get User to retrieve profile information, which displays as JSON in a result card. Tap Get Access Token to fetch an access token string without requiring a user ID. While an operation is in progress, a loading spinner appears and both buttons are disabled. Errors display in a separate card with error styling.

Key concepts

SDK service connection

All Horizon Platform SDK APIs require initialization before use. The sample calls HorizonServiceConnection.connect() in onCreate() with three parameters: your app ID, the application context, and the activity’s lifecycle scope:
HorizonServiceConnection.connect(
    APPLICATION_ID, applicationContext, lifecycleScope
)
This pattern appears in all Platform SDK samples. See MainActivity.kt for the complete implementation.

Application ID validation

The sample uses a throwing property getter for APPLICATION_ID rather than a placeholder string. The app crashes at launch until you replace it with your actual Meta app ID:
private val APPLICATION_ID: String
    get() = throw IllegalStateException(
        "Replace with your application ID"
    )
This enforces configuration before first run. See MainActivity.kt for the full pattern.

Centralized action execution

The ViewModel defines a reusable executeAction() helper that wraps all SDK calls with consistent loading state, error handling, and IO dispatching:
private fun executeAction(
    actionName: String, action: suspend () -> String
) { /* sets loading, runs on IO, catches exceptions */ }
Both getUser() and getAccessToken() delegate to this helper, eliminating duplicate coroutine and error-handling code. See UsersViewModel.kt for the complete implementation.

User API methods

The Users class provides two methods demonstrated in this sample. To retrieve user profile data, call users.get(userId) within a coroutine context — the method returns a user object with a .json property containing the raw profile data. To fetch an access token, call users.getAccessToken(), which returns a string. Both methods are called on Dispatchers.IO in the sample. See UsersViewModel.kt for usage patterns.

Immutable state updates

The sample uses MutableStateFlow with a data class for UI state. Updates use the update { it.copy(...) } pattern to ensure atomic, immutable transitions:
_uiState.update {
    it.copy(isLoading = true, errorMessage = null)
}
This approach avoids race conditions when multiple coroutines update state. See UsersViewModel.kt for complete state management.

Extend the sample

  • Add user profile parsing: Replace the raw JSON display with parsed fields like username, avatar URL, or bio using a JSON library like kotlinx.serialization.
  • Combine with User Age Category: Fetch both profile data and age category restrictions by integrating the User Age Category sample.
  • Implement token refresh flow: Use the access token to authenticate API requests and handle token expiration with automatic refresh logic.