Preload Plan¶
Preload plans in advance and reuse them later without the internet during the app lifecycle.
Overview¶
- Use
ExpoFpPlan.preloaderto preload plans. - A preloaded plan is represented by
ExpoFpPreloadedPlanInfo. - You can obtain a presenter for a preloaded plan with
getPreloadedPlanPresenter(...). - Recommended: Preload plans if you expect to reuse them multiple times in one session.
- If a preloaded plan is reloaded with a new
planLink, the link info is automatically updated in the storedExpoFpPreloadedPlanInfo.
Lifecycle Management¶
Important: Preloaded plans are NOT automatically disposed when the Activity/Fragment is destroyed. This allows you to reuse the same presenter across multiple screens without reloading.
- Preloaded plans persist in memory until you explicitly call
disposePreloadedPlan()orremoveAllPreloadedPlans().- You can safely attach and detach the same preloaded presenter to different Activities/Fragments.
- All event callbacks will continue to work after reattaching a preloaded plan.
- You are responsible for disposing preloaded plans when they are no longer needed to free memory.
Automatic Memory Management¶
Message listeners are automatically removed when the hosting Activity/Fragment is destroyed. This prevents memory leaks without requiring manual cleanup.
For preloaded presenters reused across multiple screens, you must call
setMessageListener()again in each screen'sonCreate()to receive callbacks on the new Activity/Fragment instance.If you need to remove the listener earlier (before the Activity/Fragment is destroyed), you can manually call
removeMessageListener():// Optional: Remove listener manually if needed before Activity destroy presenter?.removeMessageListener()
Step 1. Preload from the Internet¶
Coroutine version (recommended)¶
val expoKey = "YourExpoKey"
val preloadedPlanInfo = ExpoFpPlan.preloader.preloadPlan(
planLink = ExpoFpLinkType.ExpoKey(expoKey)
)
With additional parameters¶
val additionalParams = listOf(ExpoFpPlanParameter.NoOverlay(true), ExpoFpPlanParameter.HideHeaderLogo(true))
val locationProvider: IExpoFpLocationProvider = YourLocationProvider()
val messageListener: IExpoFpPlanMessageListener = YourMessageListener()
val preloadedPlanInfo = ExpoFpPlan.preloader.preloadPlan(
planLink = ExpoFpLinkType.ExpoKey("YourExpoKey"),
additionalParams = additionalParams,
locationProvider = locationProvider,
messageListener = messageListener
)
Step 2. Preload from Downloaded Plan¶
Coroutine version (recommended)¶
val preloadedPlanInfo = ExpoFpPlan.preloader.preloadPlan(
planLink = ExpoFpLinkType.DownloadedPlanInfo(downloadedPlanInfo)
)
With additional parameters¶
val additionalParams = listOf(ExpoFpPlanParameter.NoOverlay(true), ExpoFpPlanParameter.HideHeaderLogo(true))
val locationProvider: IExpoFpLocationProvider = YourLocationProvider()
val messageListener: IExpoFpPlanMessageListener = YourMessageListener()
val preloadedPlanInfo = ExpoFpPlan.preloader.preloadPlan(
planLink = ExpoFpLinkType.DownloadedPlanInfo(downloadedPlanInfo),
additionalParams = additionalParams,
locationProvider = locationProvider,
messageListener = messageListener
)
Step 3. Manage Preloaded Plans¶
Get all preloaded plans:
val preloadedPlansInfo: List<ExpoFpPreloadedPlanInfo> =
ExpoFpPlan.preloader.getPreloadedPlansInfo()
Get a presenter from a preloaded plan:
val presenter = ExpoFpPlan.preloader.getPreloadedPlanPresenter(preloadedPlanInfo)
If only one plan is preloaded, you can get it without parameters:
val presenter = ExpoFpPlan.preloader.getPreloadedPlanPresenter()
Step 4. Show Preloaded Plan¶
View-based UI¶
val planView = presenter.getView()
// IMPORTANT: If reusing a preloaded plan, remove from old parent first
(planView.parent as? ViewGroup)?.removeView(planView)
container.addView(planView)
Important Limitation:
A preloaded presenter has only ONE View instance. When you call
getView()from a different Activity/Fragment, the View is physically moved from its previous parent to the new one.This means: - You cannot display the same preloaded plan in multiple Activities/Fragments simultaneously - If you have multiple Activities in the back stack using the same preloaded presenter, only the top one will show the plan - Previous Activities will have blank/empty screens because their View was taken by the new Activity
Solution: Use
FLAG_ACTIVITY_CLEAR_TOPorsingleToplaunch mode if you need to repeatedly open the same screen with a preloaded plan.Note: When reusing a preloaded plan across multiple screens, always remove the view from its old parent before adding it to a new container. Otherwise, you'll get an
IllegalStateException: The specified child already has a parent.
Jetpack Compose¶
AndroidView(
factory = {
presenter.getView().apply {
// Remove from old parent if reusing
(parent as? ViewGroup)?.removeView(this)
}
}
)
Step 5. Delete Preloaded Plans¶
Delete a specific plan:
val presenter = ExpoFpPlan.preloader.disposePreloadedPlan(preloadedPlanInfo)
Delete all plans:
ExpoFpPlan.preloader.removeAllPreloadedPlans()
Best Practices¶
- Preload early: Preload plans during app initialization or screen preparation if you expect repeated access.
- Reuse presenters: Get presenters from preloaded plans instead of creating new ones to reduce loading time.
- Clear when not needed: Dispose preloaded plans when they are no longer needed to free memory.
- Combine with download: Download plans to disk first, then preload them for faster reuse.
Memory Management¶
Preloaded plans remain in memory until explicitly disposed:
class MainActivity : AppCompatActivity() {
private var preloadedPlanInfo: ExpoFpPreloadedPlanInfo? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Preload plan once
if (preloadedPlanInfo == null) {
preloadedPlanInfo = ExpoFpPlan.preloader.preloadPlan(
planLink = ExpoFpLinkType.ExpoKey("demo")
)
}
// Get presenter from preloaded plan
val presenter = ExpoFpPlan.preloader.getPreloadedPlanPresenter(preloadedPlanInfo)
// Attach to view - can be done multiple times across different Activities
presenter?.let {
val planView = it.getView()
container.addView(planView)
}
}
override fun onDestroy() {
super.onDestroy()
// Only dispose when you no longer need the plan
if (isFinishing) {
preloadedPlanInfo?.let {
ExpoFpPlan.preloader.disposePreloadedPlan(it)
}
}
}
}
Reusing Across Multiple Screens¶
Preloaded plans can be safely reused across different Activities or Fragments:
// Activity A
class MapActivityA : AppCompatActivity() {
private var presenter: IExpoFpPlanPresenter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
presenter = ExpoFpPlan.preloader.getPreloadedPlanPresenter(preloadedPlanInfo)
// Get the view from presenter
val planView = presenter?.getView()
// IMPORTANT: Remove from old parent if it was attached before
(planView?.parent as? ViewGroup)?.removeView(planView)
// Now add to this activity's container
container.addView(planView)
// Set message listener for this screen
presenter?.setMessageListener(myListener)
}
override fun onDestroy() {
super.onDestroy()
// Note: Message listener is automatically removed by SDK
}
}
// Activity B - reuse the same preloaded plan
class MapActivityB : AppCompatActivity() {
private var presenter: IExpoFpPlanPresenter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Get the same presenter - no reloading needed!
presenter = ExpoFpPlan.preloader.getPreloadedPlanPresenter(preloadedPlanInfo)
// Get the view from presenter
val planView = presenter?.getView()
// IMPORTANT: Remove from old parent (Activity A's container) before adding here
(planView?.parent as? ViewGroup)?.removeView(planView)
// Now add to this activity's container
container.addView(planView)
// All callbacks still work - set new listener for this screen
presenter?.setMessageListener(myListener)
}
override fun onDestroy() {
super.onDestroy()
// Note: Message listener is automatically removed by SDK
}
}
Advanced: Multiple Activities in Back Stack¶
If you have multiple Activities in the back stack that need to share the same preloaded presenter simultaneously, note that only the topmost Activity will display the plan due to the one-View-per-presenter limitation.
For this advanced scenario where you need the plan to reappear when returning to a previous Activity via the back button, you can re-attach the View in onStart():
class MapActivity : AppCompatActivity() {
private var presenter: IExpoFpPlanPresenter? = null
private var container: FrameLayout? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
presenter = ExpoFpPlan.preloader.getPreloadedPlanPresenter(preloadedPlanInfo)
// Standard pattern for initial attachment in onCreate()
// (For re-attachment on back stack return, see onStart() pattern below)
val planView = presenter?.getView()
(planView?.parent as? ViewGroup)?.removeView(planView)
// Save container reference for re-attaching later
container = FrameLayout(this).apply {
addView(planView)
}
rootView.addView(container)
presenter?.setMessageListener(myListener)
}
override fun onStart() {
super.onStart()
// Re-attach View when returning from back stack
val planView = presenter?.getView()
if (planView?.parent != container) {
(planView?.parent as? ViewGroup)?.removeView(planView)
container?.addView(planView)
}
}
override fun onDestroy() {
super.onDestroy()
// Note: Message listener is automatically removed by SDK
}
}
Note: The re-attachment pattern addresses edge cases where multiple Activities remain in the back stack with a shared preloaded presenter. For standard workflows, use
FLAG_ACTIVITY_CLEAR_TOPorsingleToplaunch mode (see Important Limitation above). StandardonCreate()attachment suffices for typical destroy/recreate cycles.