Chinese document 中文文档
FlowBus is a Kotlin Event Bus implemented using Kotlin Coroutines and Flows.
FlowBus supports the following features: Sticky Events, Thread Switching, Multiple Subscriptions, Delayed Posting, Lifecycle Awareness, and Ordered Message Reception.
| Feature | Detailed Explanation |
|---|---|
| Achieves "Sticky" Effect | When replay is set to 1, the Flow caches the most recently emitted value. Any new subscriber will immediately receive this cached value upon starting collection, even if the value was published before the subscription began. |
| Easy Thread Switching | Inside the subscribe method, lifecycleOwner.lifecycleScope.launch is used, and this.launch(dispatcher) is used again within collect to process the received event. * Collection (Collect): Can be safely started/stopped on any thread (typically the main thread/Dispatchers.Main). * Handling (Handle): Upon receiving data, it's easy to switch to a specified thread to execute time-consuming operations, thus preventing the UI thread from being blocked. |
| Multiple Subscriptions | SharedFlow is a Hot Flow that supports Multicast. The same Flow instance can be simultaneously subscribed to by multiple collect calls. When an event is published via tryEmit(), all currently active observers receive the event simultaneously. |
| Automatic Event Cleanup | When a MutableSharedFlow's replay is set to 0, published events (via tryEmit or emit) will be directly discarded if no active subscribers are listening.This effectively prevents the Event Backlog problem, stopping the application's memory usage from rising due to excessive events when there are no subscribers for a long time. |
| Lifecycle Awareness | Ensures that the coroutine block inside repeatOnLifecycle (i.e., the collect operation) is launched only when the state of the lifecycleOwner (such as an Activity/Fragment) is greater than or equal to startState. |
| Control Over Launch Timing | Allows control over when event responses should begin by passing in a specific Lifecycle.State. |
| Coroutine Suspension and Resumption | When the lifecycleOwner's state drops below startState (e.g., transitioning from STARTED to STOPPED), repeatOnLifecycle automatically cancels its internal collect coroutine. When the state returns to startState again, a new collect coroutine is automatically restarted. |
-
Add the remote repository to your Project's build.gradle or setting.gradle
repositories { // mavenCentral() }
-
Add the dependency to your Module's build.gradle
implementation 'io.github.logan0817:flowbus:1.0.1' // Replace with the latest version shown by the badge above
You can also directly download the Demo App to experience the effect.
//Global Scope
postEvent(GlobalEvent("Test GlobalEvent"))
//Activity Scope
postEvent(requireActivity(), ActivityEvent("Test ActivityEvent"))
//Fragment Scope
postEvent(this@TestFragment, FragmentEvent("Test FragmentEvent"))//延迟发送
postEvent(GlobalEvent(value = "Delay GlobalEvent"), 1000)/** subscribeForever
* subscribeForever requires specifying the coroutineScope
*/
val coroutineScope = CoroutineScope(Dispatchers.Main)
coroutineScope.subscribeEvent<GlobalEvent> {
}
/** subscribe GlobalScopeEvent
*/
subscribeEvent<GlobalEvent> {
}
/** subscribe ActivityEvent
*/
subscribeEvent<ActivityEvent>(scope = activity) {
}
/** subscribe FragmentEvent
*/
subscribeEvent<FragmentEvent>(scope = fragment) {
}
subscribeEvent<XEvent>(Dispatchers.IO) {
}subscribeEvent<XEvent>(minLifecycleState = Lifecycle.State.RESUMED) {
}subscribeEvent<XEvent>(isSticky = true) {
}/**
* Remove specified sticky event stream
*/
//In GlobalScope
removeStickyEvent<XEvent>()
//In CoroutineScope
removeStickyEvent<XEvent>(scope = coroutineScope)
//In Activity
removeStickyEvent<XEvent>(scope = activity)
//In Fragment
removeStickyEvent<XEvent>(scope = fragment)/**
* Clears the replay cache for the local sticky event type T, but keeps the Flow instance.
*/
//In GlobalScope
clearStickyEvent<GlobalEvent>()
//In CoroutineScope
clearStickyEvent<XEvent>(scope = coroutineScope)
//In Activity
clearStickyEvent<XEvent>(scope = activity)
//In Fragment
clearStickyEvent<XEvent>(scope = fragment)MIT License
Copyright (c) 2025 Logan Gan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
