https://kotlinlang.org logo
#android
Title
# android
h

Hugh Edwards

02/18/2023, 4:06 AM
Hey I’ve got a bit of an oddball question regarding android/kotlin coroutine performance, and how to optimise it. I’m new to the android scene and was hoping someone might be able to tell me if my approach is sensible or there’s a much better way of doing things.
🧵 1
I’m building an app which is ultimately controlled by a backend - the app listens on a socketio connection and that connection dictates which state the app is in, what’s happening on screen and which activities it jumps between.
My architectural setup is basically this - Main application class launches a
GlobalScope(<http://Dispatchers.IO|Dispatchers.IO>)
coroutine that initiates the socket connection, returning a flow (via callback flow) of transformed socket messages as domain objects I popped a
.flowOn(<http://dispatchers.io|dispatchers.io>)
on that callback flow (though looking again now I think that flow should already exist in the io scope..?)
Back in Main Application it looks like this
Copy code
private val _messageFlow = MutableSharedFlow<DomainMessage>()

GlobalScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
  // what ive just described above
  val flow = initiateSocketConnection()
  
  launch(Dispatchers.Default) {
    flow.collect { message -> 
      _messageFlow.emit(message)
    }
  }
}
Reason for this is I want activities to be able to subscribe to the flow in the application class immediately without having to wait for it to be instantiated first And basically everywhere in the app I read from this message flow on dispatchers default and react to it Is this sensible? Is there a way I could reduce latency from socketio / is my dispatcher choice sensible? I find all the scopes/contexts/dispatchers and coroutine stuff pretty tricky to navigate to be honest
s

s3rius

02/20/2023, 10:11 PM
So I guess you want to avoid
initiateSocketConnection
to be called a bunch of times. In that case it seems sensible to use a shared flow. The pattern you are after (collect everything from a flow and put it in a shared flow) you can use shareIn. The example even has something pretty close to what you're building. So it could roughly look like this
Copy code
public val messageFlow = initiateSocketConnection()
    .shareIn(GlobalScope, SharingStarted.Eagerly, 0)
Although do take a closer look at the parameters
Since you're on Android you probably also want to think about whether you really want the flow to be ongoing at all times. E.g. if your app is in background. Depending on what you do with those backend messages, it might be more efficient to drop the connection while the app is in a state where you are not consuming these messages. In this case you can experiment with
SharingStated.WhileSubscribed()
h

Hugh Edwards

02/21/2023, 12:04 AM
Yeah that initiate call only happens once That sharein is interesting, I’ll check it out
I basically need to respond to every backend message and they could come in at any time Battery or optimisation isn’t a concern, really performance and stability
11 Views