> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encorekit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Android Integration Patterns

> Two ways to handle Encore offer results in Kotlin — async-result and handler-based — with a decision tree for picking the right one.

## Overview

`Encore.placement(id).show()` is a `suspend` function that returns a `PresentationResult`. You can either branch on it at the call site (async-result) or register global `onPurchaseRequest` / `onPassthrough` handlers (handler-based). Both work; pick whichever fits the call site.

For the cross-platform decision tree, see [Integration Patterns](/concepts/integration-patterns).

***

## Async-result pattern

Use this when the place you call `show()` from already has access to your purchase + decline logic.

### Basic example

```kotlin theme={null}
import androidx.lifecycle.lifecycleScope
import com.encorekit.encore.Encore
import com.encorekit.encore.features.offers.PresentationResult
import kotlinx.coroutines.launch

class CancelActivity : AppCompatActivity() {
    fun onCancelTapped() {
        lifecycleScope.launch {
            val result = Encore.placement("cancel_flow").show()
            when (result) {
                is PresentationResult.Completed -> {
                    // User completed an offer — navigate home
                    finish()
                }
                is PresentationResult.Dismissed -> {
                    // User dismissed — proceed with original flow
                    proceedWithCancellation(result.reason)
                }
                is PresentationResult.NoOffers -> {
                    // No offers available — proceed with original flow
                    proceedWithCancellation(null)
                }
            }
            // Code that runs in all branches lives here, written once
            analytics.track("cancel_flow_resolved")
        }
    }
}
```

### From Compose

`onClick` is synchronous, so launch a coroutine on the lifecycle scope:

```kotlin theme={null}
@Composable
fun CancelButton() {
    val activity = LocalContext.current as ComponentActivity
    val scope = rememberCoroutineScope()

    Button(onClick = {
        scope.launch {
            val result = Encore.placement("cancel_flow").show()
            when (result) {
                is PresentationResult.Completed -> activity.finish()
                is PresentationResult.Dismissed,
                is PresentationResult.NoOffers -> proceedWithCancellation()
            }
        }
    }) { Text("Cancel Subscription") }
}
```

### Result type

```kotlin theme={null}
sealed class PresentationResult {
    data class Completed(val offerId: String, val campaignId: String?) : PresentationResult()
    data class Dismissed(val reason: DismissReason) : PresentationResult()
    data object NoOffers : PresentationResult()
}

enum class DismissReason(val value: String) {
    USER_CLOSED("user_closed"),
    NO_OFFERS("no_offer_available"),
    ERROR("error"),
}
```

See [PresentationResult](../sdk-reference/presentation-result).

***

## Handler pattern

Use this when the `show()` call site is a third-party delegate or a UI action that doesn't have direct access to your purchase code.

### Register in `Application.onCreate()`

```kotlin theme={null}
import android.app.Application
import com.encorekit.encore.Encore

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()

        Encore.configure(this, apiKey = "pk_live_...")

        Encore.shared.onPurchaseRequest { request ->
            // Route to RevenueCat / Adapty / Play Billing
            billingManager.purchase(request.productId)
        }

        Encore.shared.onPassthrough { placementId ->
            // Resume the user's original flow
            AppRouter.handlePassthrough(placementId)
        }
    }
}
```

### Then `show()` from anywhere

```kotlin theme={null}
Button(onClick = {
    scope.launch { Encore.placement("cancel_flow").show() }
}) { Text("Cancel Subscription") }
```

The handlers fire when the placement resolves. Code at the call site doesn't need to inspect the returned result.

***

## When to use which

* **Async-result** — call site already imports your billing client. Branch-specific code lives at the call site.
* **Handler** — Encore is invoked from third-party paywall delegates or from many UI sites that share post-purchase logic.
* **Mixed** — handlers handle cross-cutting analytics; specific call sites still branch on `show()`.

See the [decision tree](/concepts/integration-patterns#decision-tree) for the full rationale.

***

## Re-registration semantics

```kotlin theme={null}
Encore.shared.onPurchaseRequest { /* v1 */ }
Encore.shared.onPurchaseRequest { /* v2 — replaces v1 */ }
```

Each setter replaces the previous lambda. No double-fires.

***

## Platform-specific notes

* **`show()` is `suspend`** — call from a coroutine scope (`lifecycleScope`, `viewModelScope`, `rememberCoroutineScope()`). The no-arg overload auto-resolves the current foreground Activity; the explicit `show(activity: Activity)` overload is also available if you need to bind to a specific Activity.
* **Fire-and-forget overload** — `Encore.placement(id).show(scope)` exists if you don't want to await the result. Equivalent to launching with the handler pattern.
* **`PresentationResult.Completed` carries `offerId` and `campaignId`** — the entitlement claim is applied by the SDK; the result fields are for your own analytics.
* **`Dismissed` vs `NoOffers`** — `NoOffers` fires when the API returns zero offers for this user; `Dismissed(DismissReason.USER_CLOSED)` fires when the user closes a sheet that did have offers. `Dismissed(DismissReason.ERROR)` covers presentation failures (e.g., no foreground Activity).
* **JVM target** — the SDK is built with JVM target 17. Your app must match (most modern Android Gradle plugins default to this).

***

## See also

* [Concepts — Integration Patterns](/concepts/integration-patterns) — cross-platform decision tree
* [Quickstart — Present Offers](/publishers/android/quickstart/present-offers) — handler-pattern walkthrough
* [SDK Reference — `placement()`](../sdk-reference/placement)
* [SDK Reference — `PresentationResult`](../sdk-reference/presentation-result)
