I am using Hilt and implementing socket.
Here's the repository Module for creating repos.
@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {
@Provides
fun provideSocketRepository(socket: Socket): SocketRepository {
return SocketRepository(socket)
}
}
And here's ServiceModule to inject Socket to SocketRepository.
@Module
@InstallIn(SingletonComponent::class)
object ServiceModule {
@Provides
fun provideSocket(): Socket {
logd("socket: accessToken: ${Common.accessToken}")
val options = IO.Options().apply {
timeout = 30000
reconnection = true
reconnectionDelay = 1000
reconnectionAttempts = 300
transports = arrayOf(WebSocket.NAME)
extraHeaders = mapOf(
"Authorization" to listOf("Bearer ${Common.accessToken}"),
"Content-Type" to listOf("application/json"),
"identity" to listOf("app")
)
}
return IO.socket(UrlType.BACK_OFFICE_SERVER.getUrl(), options)
}
}
The problem is
Common.accessToken
is global variable which needs refactoring and also it's updated after sign in. However, Socket is needed globally for entire app process. So, the timing is after injection. How can it get the latest accessToken using hilt?
I should connect & disconnect Socket programmatically at some points. If I use hilt it will keep injecting to the repo class. Is it Okay the instance to be alive when I try to disconnect it? for example, socket.disconnect
without socket = null
and then socket.connect
to reconnect socket when it needs to be connected.
In your case, Socket
shouldn't be injected, instead it is wrapped in a Manager class which will handle the logic and being injected into Repositories.
You can have an singleton AuthManager
class which controls the login and token flow (you can define the module yourself):
class AuthManager @Inject constructor() {
val token = MutableStateFlow<String?>(null)
suspend fun signIn() {
// Do sign in stuff, then update your token
token.emit(newToken)
}
}
Then your SocketManager
class has AuthManager
as dependencies:
class SocketManager @Inject constructor(authManager: AuthManager) {
val socket = MutableStateFlow<Socket?>(null)
init {
authManager.token.collect {
// Token updated, recreated your socket here and emit new socket to collector
socket.emit or socket.trySend
}
}
}
SocketManager
is Singleton too (you can define the Module yourself)
Lastly, anywhere you want to use the socket, like in Activity
, inject SocketManager
and collect the socket as needed:
@AndroidEntryPoint
class MyActivity: AppCompatActivity {
@Inject
lateinit var socketManager: SocketManager
fun onCreate() {
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
socketManager.socket.collect {
// Use your socket here, socket will be changed after token changed and this code block is called
}
}
}
}
}