Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

198
Views
Do I need to warp the collectAsState() of a hot Flow with repeatOnLifecycle in @Composable?

I have read the article A safer way to collect flows from Android UIs.

I know the following content.

A cold flow backed by a channel or using operators with buffers such as buffer, conflate, flowOn, or shareIn is not safe to collect with some of the existing APIs such as CoroutineScope.launch, Flow.launchIn, or LifecycleCoroutineScope.launchWhenX, unless you manually cancel the Job that started the coroutine when the activity goes to the background. These APIs will keep the underlying flow producer active while emitting items into the buffer in the background, and thus wasting resources.

The Code A is from the official sample project.

The viewModel.suggestedDestinations is a MutableStateFlow, it's a hot Flow.

I don't know if the operation collectAsState() of hot Flow is safe in @Composable UI.

1: Do I need to use the Code just like Code B or Code C replace Code A for a hot Flow?

2: Is the operation collectAsState() of cold Flow safe in @Composable UI.

Code A

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun CraneHomeContent(
    onExploreItemClicked: OnExploreItemClicked,
    openDrawer: () -> Unit,
    modifier: Modifier = Modifier,
    viewModel: MainViewModel = viewModel(),
) {
    val suggestedDestinations by viewModel.suggestedDestinations.collectAsState()

    ...
    
}


@HiltViewModel
class MainViewModel @Inject constructor(
    ...
) : ViewModel() {
    ...
    private val _suggestedDestinations = MutableStateFlow<List<ExploreModel>>(emptyList())
    val suggestedDestinations: StateFlow<List<ExploreModel>>
}

Code B

class LocationActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)      
        lifecycleScope.launch {        
            repeatOnLifecycle(Lifecycle.State.STARTED) {               
               ...
            }
        }
    }
}

Code C

@Composable
fun LocationScreen(locationFlow: Flow<Flow>) {
   val lifecycleOwner = LocalLifecycleOwner.current
   val locationFlowLifecycleAware = remember(locationFlow, lifecycleOwner) {
        locationFlow.flowWithLifecycle(lifecycleOwner.lifecycle, Lifecycle.State.STARTED)
     }
   val location by locationFlowLifecycleAware.collectAsState()    
     ...
}
over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

collectAsState (Code A) is safe for any kind of Flow (cold/hot it doesn't matter). If you look at how collectAsState is implemented then you will see that it uses a LaunchedEffect deep down (collectAsState -> produceState -> LaunchedEffect)

internal class LaunchedEffectImpl(
    parentCoroutineContext: CoroutineContext,
    private val task: suspend CoroutineScope.() -> Unit
) : RememberObserver {
    private val scope = CoroutineScope(parentCoroutineContext)
    private var job: Job? = null

    override fun onRemembered() {
        job?.cancel("Old job was still running!")
        job = scope.launch(block = task)
    }

    override fun onForgotten() {
        job?.cancel()
        job = null
    }

    override fun onAbandoned() {
        job?.cancel()
        job = null
    }
}

which creates a coroutine scope and launches the task lambda once it enters the composition and cancels it automatically once it leaves the composition.

In Code A, viewModel.suggestedDestinations.collectAsState() (together with it's LaunchedEffect and it's coroutine scope) will be active as long as CraneHomeContent is being called by some other code. As soon as CraneHomeContent is stopped being called the LaunchedEffect inside of collectAsState() is canceled (and coroutine scope as well).

If it's called from multiple places then there will be multiple LaunchedEffects and thus multiple coroutine scopes.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!