-
public class OneSignalDispatchersOptimized threading manager for the OneSignal SDK.
Performance optimizations:
Lazy initialization to reduce startup overhead
Custom thread pools for both IO and Default operations
Optimized thread pool configuration (smaller pools)
Small bounded queues (10 tasks) to prevent memory bloat
Reduced context switching overhead
Efficient thread management with controlled resource usage
Made public to allow mocking in tests via IOMockHelper.
-
-
Field Summary
Fields Modifier and Type Field Description private final CoroutineDispatcherIOprivate final CoroutineDispatcherDefaultprivate final CoroutineDispatcherSerialIOpublic final static OneSignalDispatchersINSTANCE
-
Method Summary
Modifier and Type Method Description final JoblaunchOnIO(SuspendFunction0<Unit> block)final JoblaunchOnDefault(SuspendFunction0<Unit> block)final JoblaunchOnSerialIO(SuspendFunction0<Unit> block)Launches block on the single-thread serial IO dispatcher (FIFO across all callers). final Unitprewarm()Triggers the lazy initialization of IO, Default, and SerialIO (and their backing executors, dispatchers, and scopes) on a short-lived background thread. final CoroutineDispatchergetIO()final CoroutineDispatchergetDefault()final CoroutineDispatchergetSerialIO()-
-
Method Detail
-
launchOnIO
final Job launchOnIO(SuspendFunction0<Unit> block)
-
launchOnDefault
final Job launchOnDefault(SuspendFunction0<Unit> block)
-
launchOnSerialIO
final Job launchOnSerialIO(SuspendFunction0<Unit> block)
Launches block on the single-thread serial IO dispatcher (FIFO across all callers).
-
prewarm
final Unit prewarm()
Triggers the lazy initialization of IO, Default, and SerialIO (and their backing executors, dispatchers, and scopes) on a short-lived background thread.
Background: The lazy
by lazyproperties below constructThreadPoolExecutorinstances and wrap them inasCoroutineDispatcher() + SupervisorJob() + CoroutineScope(...). Production OTel shows that when the first caller of launchOnIO / launchOnSerialIO is on the main thread (Activity-lifecycle handler,JobService.onStartJob, etc.), the construction cost — which includes akotlinx.coroutines.BuildersKt.launchthat hitsThreadPoolExecutor.executeandLinkedBlockingQueue.offersynchronously — is paid on the calling thread, blocking the main thread for many seconds on cold start. See SDK-4507.Calling prewarm from a non-time-sensitive spot in com.onesignal.OneSignal.initWithContext shifts that cost to a dedicated
OneSignal-prewarmdaemon thread, so the first production caller — including main-thread lifecycle handlers — only pays the much cheaper "submit work to an already-constructed executor" cost.Idempotent and fire-and-forget: a no-op on second and subsequent calls. Safe to invoke from any thread; the heavy lifting always happens on the daemon thread we spawn here, not on the caller. Failures are logged and swallowed because the executors retain their existing fallback paths (e.g.
Dispatchers.IO.limitedParallelism(1)for SerialIO) and a failed prewarm will simply mean the first production caller pays the original cost.
-
getIO
final CoroutineDispatcher getIO()
-
getDefault
final CoroutineDispatcher getDefault()
-
getSerialIO
final CoroutineDispatcher getSerialIO()
-
-
-
-