Problem
startMobileApp sets up the platform context (Android JNI env, files directory, etc.) before invoking any callbacks. But the MobileApp value must be fully constructed before calling startMobileApp, so there is no way to run IO that depends on the platform context during app setup.
This forces consumer apps to use either:
Both are awkward. The IORef cache adds complexity, and the lazy init means the first render pays the full DB setup cost.
Proposed solution
Change startMobileApp to accept an IO MobileApp builder instead of a plain MobileApp:
-- before
startMobileApp :: MobileApp -> IO (Ptr AppContext)
-- after
startMobileApp :: IO MobileApp -> IO (Ptr AppContext)
startMobileApp would set up the platform context first, then run the IO MobileApp action to let the consumer build its app with full filesystem/JNI access, then proceed with the first render.
This lets consumer apps construct state eagerly:
main = startMobileApp $ do
actionState <- newActionState
appState <- withDatabase $ \conn -> do
initDB conn
loadRecords conn >>= newAppState
appActions <- runActionM actionState (createAppActions appState)
pure MobileApp
{ maContext = ...
, maView = \userState -> appRootView appActions appState
, maActionState = actionState
}
No unsafePerformIO, no deferred caching, no lazy init on first render.
Context
Discovered while removing unsafePerformIO globals from prrrrrrrrr (jappeace/prrrrrrrrr#60). The app crashed on Android because get_app_files_dir was called before startMobileApp had set up the JNI context.
Problem
startMobileAppsets up the platform context (Android JNI env, files directory, etc.) before invoking any callbacks. But theMobileAppvalue must be fully constructed before callingstartMobileApp, so there is no way to run IO that depends on the platform context during app setup.This forces consumer apps to use either:
unsafePerformIOglobals with lazy init (the old prrrrrrrrr approach)IORef (Maybe a)pattern to defer init to the firstmaViewcall (the current prrrrrrrrr approach, see Eliminate unsafePerformIO globals from Hatter.App prrrrrrrrr#60)Both are awkward. The
IORefcache adds complexity, and the lazy init means the first render pays the full DB setup cost.Proposed solution
Change
startMobileAppto accept anIO MobileAppbuilder instead of a plainMobileApp:startMobileAppwould set up the platform context first, then run theIO MobileAppaction to let the consumer build its app with full filesystem/JNI access, then proceed with the first render.This lets consumer apps construct state eagerly:
No
unsafePerformIO, no deferred caching, no lazy init on first render.Context
Discovered while removing
unsafePerformIOglobals from prrrrrrrrr (jappeace/prrrrrrrrr#60). The app crashed on Android becauseget_app_files_dirwas called beforestartMobileApphad set up the JNI context.