Is it OK to launch coroutines from Globalscope on Android in certain situations (singletons)?

后端 未结 2 1989
旧时难觅i
旧时难觅i 2021-02-20 07:10

When launching coroutines from Activities, Fragments or Android Architecture Components ViewModels, it makes total sense to use a coroutine scope that is bound to the lifecycle

相关标签:
2条回答
  • 2021-02-20 07:14

    If you have an asynchronous worker whose lifecycles is truly global (they only die/end when your process dies), using GlobalScope or a similar life-long scope, is fine.

    Say, you have an Activity that makes a request, but the actual network-request needs to continue even if the Activity goes away, because you'd like to cache it when the network finally returns a response.

    You'll add a CoroutineScope to your Activity/Fragment, or better to your ViewModel and have your code that finally puts stuff on the screen run in that scope. When the Activity/Fragment/ViewModel dies, the scope is canceled and nothing will be attempted to show something on a screen that no longer exists.

    However, your Fragment/Activity/ViewModel may talk to a data-source/repository that has a lifecycle that only ends when the process dies. You can switch to a GlobalScope in there so that your network-responses get cached, even when no Activity/Fragment/ViewModel is alive to show the result on the screen.

    class MyViewModel(context: CoroutineContext, repo: MyRepository) : ViewModel() {
        private val scope = CoroutineScope(context + SuperviserJob())
    
        override fun onCleared() { scope.cancel() }
    
        fun getDataFromNetwork() {
            scope.launch {
                myLiveData.value = repo.getDataFromNetwork()
            }
        }
    
    }
    
    // Singleton class
    class MyRepositoryImpl(context: CoroutineContext) : MyRepository {
        private val scope = CoroutineScope(context + SupervisorJob())
    
        override suspend fun getDataFromNetwork() : String {
            return scope.async { // switch scopes
                val data = ... fetch data ...
                saveInCache(data)
            }.await()
        }
    }
    

    When your ViewModel ends (onCleared is called), the MyRepositoryImpl's getDataFromNetwork still keeps running and will call saveInCache if all goes right. However, the value returned won't be assigned to myLiveData.value because the coroutine of your ViewModel's scope was cancelled.

    0 讨论(0)
  • 2021-02-20 07:20

    Given that you're already trying to attach it to application's lifecycle, I'd suggest either passing the scope to your singleton or implementing a coroutinescope by it. Unfortunately, running coroutines on GlobalScope still might end in leaks. See this great article by Roman Elizarov for more info: https://medium.com/@elizarov/the-reason-to-avoid-globalscope-835337445abc

    0 讨论(0)
提交回复
热议问题