Listen Plan Events¶
Listen and respond to user interactions and runtime messages from a plan.
Overview¶
- Implement
IExpoFpPlanMessageListenerto receive event callbacks. - Assign the listener when creating the presenter (recommended) or later via
setMessageListener(...). - Callbacks are invoked on the main thread.
- The SDK does not retain your listener globally; manage its lifecycle in your UI/component.
Step 1. Implement a Listener¶
class YourListener : IExpoFpPlanMessageListener {
override fun bookmarkDidClick(
bookmark: ExpoFpResult<ExpoFpBookmark>,
from: ExpoFpLinkType
) {
// Handle bookmark click (success or error)
}
override fun boothDidClick(
boothEvent: ExpoFpResult<ExpoFpBoothClickEvent>,
from: ExpoFpLinkType
) { /* ... */ }
override fun categoryDidClick(
category: ExpoFpResult<ExpoFpCategory>,
from: ExpoFpLinkType
) { /* ... */ }
override fun currentFloorDidChange(
floor: ExpoFpResult<ExpoFpFloor>,
from: ExpoFpLinkType
) { /* ... */ }
override fun currentPositionDidChange(
position: ExpoFpResult<ExpoFpPosition>,
from: ExpoFpLinkType
) { /* ... */ }
override fun detailsDidClick(
details: ExpoFpResult<ExpoFpDetails?>,
from: ExpoFpLinkType
) { /* ... */ } // details may be null
override fun directionDidBuild(
direction: ExpoFpResult<ExpoFpDirection?>,
from: ExpoFpLinkType
) { /* ... */ } // direction may be null (reset)
override fun exhibitorCustomButtonDidClick(
buttonEvent: ExpoFpResult<ExpoFpCustomButtonEvent>,
from: ExpoFpLinkType
) { /* ... */ }
override fun visitedDidClick(
visitedEvent: ExpoFpResult<ExpoFpVisitedClickEvent>,
from: ExpoFpLinkType
) { /* ... */ }
// Debug-only (fires only in debug mode, see below)
override fun windowErrorDidReceive(
error: ExpoFpResult<ExpoFpWindowError>,
from: ExpoFpLinkType
) { /* ... */ }
override fun consoleMessageDidReceive(
message: ExpoFpResult<ExpoFpConsoleMessage>,
from: ExpoFpLinkType
) { /* ... */ }
}
Step 2. Attach the Listener¶
Recommended: set during presenter creation¶
val listener = YourListener()
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.ExpoKey("demo"),
messageListener = listener
)
Alternatively: set after creation¶
// Keep a strong reference to the listener; the SDK does not retain it.
val listener = YourListener()
presenter.setMessageListener(listener)
// Later, to remove:
presenter.removeMessageListener()
Tip: Attaching the listener at creation ensures you do not miss early events during initial loading.
Listener lifecycle¶
The SDK does not retain the message listener. Keep your own strong reference to it for as long as you need callbacks.
You can manually call
removeMessageListener()to clear the listener earlier if needed.
Step 3. Use in UI¶
View-based UI (Activity/Fragment)¶
class MainActivity : AppCompatActivity() {
private lateinit var presenter: IExpoFpPlanPresenter
private val listener = YourListener()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ExpoFpPlan.initialize(this)
presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.ExpoKey("demo"),
messageListener = listener
)
val expoView = ExpoFpView(this).apply { attachPresenter(presenter) }
setContentView(expoView)
}
override fun onDestroy() {
super.onDestroy()
// Note: a non-preloaded presenter is disposed automatically on destroy; no manual cleanup needed.
}
}
Jetpack Compose¶
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ExpoFpPlan.initialize(this)
val listener = YourListener()
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.ExpoKey("demo"),
messageListener = listener
)
setContent {
AndroidView(factory = { presenter.getView() })
}
}
}
Events Reference¶
| Event (method) | Payload type | Notes |
|---|---|---|
bookmarkDidClick(bookmark, from) |
ExpoFpResult<ExpoFpBookmark> |
User tapped a bookmark. |
boothDidClick(boothEvent, from) |
ExpoFpResult<ExpoFpBoothClickEvent> |
Booth pressed on the plan. |
categoryDidClick(category, from) |
ExpoFpResult<ExpoFpCategory> |
Category selected. |
currentFloorDidChange(floor, from) |
ExpoFpResult<ExpoFpFloor> |
Current floor changed. |
currentPositionDidChange(position, from) |
ExpoFpResult<ExpoFpPosition> |
Position updates (if location provider is active). |
detailsDidClick(details, from) |
ExpoFpResult<ExpoFpDetails?> |
Details selected/deselected. null means deselected. |
directionDidBuild(direction, from) |
ExpoFpResult<ExpoFpDirection?> |
Direction built or reset. null on reset. |
exhibitorCustomButtonDidClick(buttonEvent, from) |
ExpoFpResult<ExpoFpCustomButtonEvent> |
Custom button pressed. |
visitedDidClick(visitedEvent, from) |
ExpoFpResult<ExpoFpVisitedClickEvent> |
Visited pressed. |
windowErrorDidReceive(error, from) |
ExpoFpResult<ExpoFpWindowError> |
Debug only: JS window.onerror. |
consoleMessageDidReceive(message, from) |
ExpoFpResult<ExpoFpConsoleMessage> |
Debug only: Web console messages. |
About
ExpoFpResult<T>
Handle bothsuccessanderrorbranches. Do not assume success-only callbacks. Treat nullable payloads (T?) accordingly.
Debug-only Events¶
//create
val presenter = ExpoFpPlan.createPlanPresenter(
planLink = ExpoFpLinkType.ExpoKey("demo"),
isDebugModeEnabled = true
)
//reload
presenter.reloadPlan(
isDebugModeEnabled = true
)
- WebView
window.onerror:windowErrorDidReceive(error, from)→ExpoFpResult<ExpoFpWindowError> - Web
consolemessages:consoleMessageDidReceive(message, from)→ExpoFpResult<ExpoFpConsoleMessage>
Note: Debug mode can slow down initialization and increase logging. Use it only in debug builds.
Best Practices¶
- Attach early: Provide
messageListenerincreatePlanPresenter(...)to capture early lifecycle events. - Main thread work: Keep callbacks lightweight; offload heavy work to background coroutines.
- Lifecycle ownership: Create and remove the listener with your screen/component lifecycle to prevent leaks.
- Null-aware handling: Some payloads can be
null(e.g.,details,directionon reset). Check before use. - Error-aware handling: Always handle
ExpoFpResulterrors (network, parsing, etc.). - Debug mode: Enable only when troubleshooting. Disable in production.