Skip to main content

Overview

Encore.placement(id).show() returns a PresentationResult: the complete factual record of the presentation. It never throws, and it resolves exactly once. Three rules cover almost every integration:
  1. Invoke show() from the right context. The call is safe from any thread or scope, but it needs a foreground Activity. The callback form is always delivered on the main thread; the suspending form resumes in your caller’s context.
  2. Results are values: await inline for control flow. Branch on the record where the call site already owns what happens next, or take the callback form when the call site isn’t a coroutine.
  3. Encore.outcomes is for passive observers. Analytics, logging, and entitlement sync consume the stream instead of owning a call site.
Mixing is fine. The outcomes stream can feed telemetry while awaited results drive control flow on the same placement.

Await the result

Use this when the place you call show() from already owns the follow-up logic.

Basic example

There is no SDK-computed “unlocked” verdict; branch on the raw facts (see PresentationResult). When the mechanism detail matters, read the record:

From Compose

onClick is synchronous, so launch a coroutine on the lifecycle scope:
See PresentationResult for the full record and fact readers.

Callback form

Use this when the call site isn’t a coroutine and you don’t want to manage a scope. The callback is delivered exactly once, on the main thread:
Result delivery is not foreground-gated: the callback fires even if your Activity backgrounded mid-flow, so don’t touch views without checking your own lifecycle.

The outcomes stream

For observation that shouldn’t live at every call site, collect Encore.outcomes once, right after configure(). There is no replay, so subscribe at startup:
The stream observes; it never drives control flow. Fallback logic (proceed with the cancellation, show your own paywall) belongs at the call site, off the returned result.

Platform-specific notes

  • show() never throws. Every failure is a value: NotPresented(reason), with errors carried as NotPresentedReason.Error. There is no need for a try/catch around any show() call.
  • show() is safe to call from any thread or scope. The suspending form does its work on a background dispatcher and hops to Main internally. The callback form is always delivered on the main thread; the suspending form resumes in your caller’s context.
  • The no-arg overloads auto-resolve the current foreground Activity. show(activity) and show(activity) { result -> } are available when you need to bind to a specific one. Nothing in the foreground resolves to NotPresented(NoForegroundActivity).
  • Purchases run through your registered EncorePurchaseController. There is no billing code path inside the SDK, so the awaited result’s publisher axis is your own controller’s verdict reflected back.
  • JVM target: the SDK is built with JVM target 17. Your app must match (most modern Android Gradle plugins default to this).

See also