Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android generalized function for state flow in fragment

I am using StateFlow in my app and in my Fragment I use this to -

private var job: Job? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        job = lifecycleScope.launchWhenResumed {
            viewModel.getData().collect {
                // ...
            }
        }
    }

    override fun onPause() {
        job?.cancel()
        super.onPause()
    }

As you see I cancel the job in onPause. How could I use a generalized function so that I can avoid doing the job?.cancel in every fragment.

I prefer not to use a BaseFragment

like image 656
Ma2340 Avatar asked Jul 14 '26 17:07

Ma2340


2 Answers

a new way:

   // Start a coroutine in the lifecycle scope
    lifecycleScope.launch {
        // repeatOnLifecycle launches the block in a new coroutine every time the
        // lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.
        repeatOnLifecycle(Lifecycle.State.STARTED) {
        }
     }
like image 129
jack guan Avatar answered Jul 17 '26 15:07

jack guan


A simple solution would be to utilize the fragments lifecycle to automatically cancel the job when it is paused.

fun CoroutineScope.launchUntilPaused(lifecycleOwner: LifecycleOwner, block: suspend CoroutineScope.() -> Unit){
    val job = launch(block = block)
    lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
        override fun onPause(owner: LifecycleOwner) {
            job.cancel()
            lifecycleOwner.lifecycle.removeObserver(this)
        }
    })
}

//Usage
class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        lifecycleScope.launchUntilPaused(this){
            someFlow.collect{
                ...
            }
        }
    }
}

If you have many of these jobs per fragment, I would advice to use a custom CoroutineScope instead, to avoid having many lifecycle observers active.

class CancelOnPauseScope(lifecycleOwner: LifecycleOwner): CoroutineScope by MainScope(){
    init{
        lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver{
            override fun onPause(owner: LifecycleOwner) {
                cancel()
                lifecycleOwner.lifecycle.removeObserver(this)
            }
        })
    }
}

class MyFragment: Fragment() {
    private val scope = CancelOnPauseScope(this)
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        scope.launch{
            someFlow.collect{
                ...
            }
        }
    }
}
like image 29
Adrian K Avatar answered Jul 17 '26 15:07

Adrian K



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!