I'm trying to write some reconnection logic for th...
# compose
c
I'm trying to write some reconnection logic for this piece of hardware I'm connecting to. I currently have the following which works... but I'm not sure why. My constraints: 1. retry every 3 seconds 2. When app is backgrounded... stop retrying 3. When app comes back to foreground, continue retrying 4. CMP
Copy code
LaunchedEffect(unitConnected) {
        lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
            while (true) {
                delay(3_000)
                if (!unitConnected) {
                    HardwareComponent.reconnect()
                }
            }
        }
    }
I'm mostly confused to how the above works because I would have thought that once it's backgrounded it would keep going and I'm confused at how it knows to stop the loop?
w
The coroutine scope gets cancelled when the lifecycle falls below the specified event. And launched again when it reaches it again.
You probably don't want while true here though. Probably while not connected? To avoid keeping the job going every 3 seconds even when the user is already connected.
c
aha. so
repeatOnLifecycle(Lifecycle.State.RESUMED)
is a "scope"
w
A small suggestion, it's okay to use the fact that you are in "reactive" code. It's very normal to simply return if you're not interested in a state.
Copy code
LaunchedEffect(unitConnected) {
        if (!unitConnected) return@LaunchedEffect
        // Now in the following code, you have the guarantee that this only runs while `unitIsConnected`
        lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
            while (true) {
                delay(3.seconds)
                HardwareComponent.reconnect()
            }
        }
    }
Ideally Android would provide some useful flows for lifecycle state, but sadly they don't otherwise you could simply have done:
Copy code
LaunchedEffect(unitConnected) {
        if (!unitConnected) return@LaunchedEffect
        // Now in the following code, you have the guarantee that this only runs while `unitIsConnected`
        lifecycleOwner.lifeCycleFlowThatSadlyDoesNotExist().collectLatest { lifeCycleState ->
            if (!lifeCycleState.meansThatAppIsOnForeground()) return@collectLatest
            // Now in the following code, you have the guarantee that this only runs while the app is in foreground
            while (true) {
                delay(3.seconds)
                HardwareComponent.reconnect() // Only runs while `unitIsConnected` and app is in foreground! Yay!
            }
        }
    }
👀 1
f
if you want to run code when a certain lifecycle level is reached, you can use
LifecycleEffect
. There is also
LifecycleResumeEffect
and
LIfecycleStartEffect
for those 2 specific events.
🔥 1
c
I think when I tried using those my code wouldn't be cancelled though
f
cancellation is cooperative in coroutines, so you would have to check for cancellation, could that be the issue?
as shown here these effects use a lifecycle observer and, when the state reaches the desired one (start or resumed), they trigger the lambda. When the state drops below the target, it calls the clean-up lambda (also called if the effect leaves the composition before dropping below the target state)
w
cancellation is cooperative in coroutines, so you would have to check for cancellation, could that be the issue?
Many functions check for cancellation under the hood. Including
delay
. So yes, in this case it's fine
f
yes, in this example above, but we don't know if that's exactly the same code that was tried with the lifecycle effects, so it was worth mentioning
w
Sorry, I was out of context. You're right