Search code examples
androidkotlin-coroutinesandroid-lifecycle

Cant add fragment inside of lifecycleScope coroutine


I am using lifecycleScope.launch in my activity's onCreate to collect a flow but I also am trying to attach a fragment inside the scope but I just get a black screen when trying to do this like it never gets attached.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    setContentView(R.layout.main_activity)

    lifecycleScope.launch {
        _viewModel.listenForScheduleChanges().flowWithLifecycle(lifecycle, Lifecycle.State.STARTED).collect {

        }

        _viewModel.loadConfig() // suspend method that loads information

        _webFragment = WebFragment().apply {
            arguments = Bundle().apply {
                putParcelable("config", _viewModel.config)
            }
        }

        supportFragmentManager.beginTransaction()
            .replace(R.id.contentPanel, _webFragment!!)
            .commit()
    }

}

If I dont use lifecycleScope and implement CoroutineScope in my activity with that coroutine scope the fragment attaches fine

class MainActivity : AppCompatActivity(), CoroutineScope{

    private val job = SupervisorJob()
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.main_activity)

        lifecycleScope.launch {
            _viewModel.listenForScheduleChanges().flowWithLifecycle(lifecycle, Lifecycle.State.STARTED).collect {

            }
        }

        launch {
            _viewModel.loadConfig() // suspend method that loads information

            _webFragment = WebFragment().apply {
                arguments = Bundle().apply {
                    putParcelable("config", _viewModel.config)
                }
            }

            supportFragmentManager.beginTransaction()
                .replace(R.id.contentPanel, _webFragment!!)
                .commit()
        }

    }

}

I dont understand why, both appear to be using the same context with the Dispatcher as Main.

Can someone provide insight here?


Solution

  • Separate the code that collects data from flow to another coroutine scope your problem will be solved:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        setContentView(R.layout.main_activity)
    
        lifecycleScope.launch {
                viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                    _viewModel.listenForScheduleChanges().collect {
    
                    }
                }
        }
    
        lifecycleScope.launch {
           
            _viewModel.loadConfig() // suspend method that loads information
    
            _webFragment = WebFragment().apply {
                arguments = Bundle().apply {
                    putParcelable("config", _viewModel.config)
                }
            }
    
            supportFragmentManager.beginTransaction()
                .replace(R.id.contentPanel, _webFragment!!)
                .commit()
        }
    
    }
    

    the issue is that when you collect a flow in this way it blocks the whole scope and other codes in the scope are not running.