How to launch a coroutine from within a class without using init?

Viewed 617

I've got the following class:

class SomeApiRemoteSource (private var someApi: SomeApi)
{
    private val someData = MutableLiveData<Map<String, String>>()
    
    init 
    {
        GlobalScope.launch(Dispatchers.IO)
        {
            try
            {
                val response = someApi.getSomeData(SomeApi.API_KEY).awaitResponse()
    
                if(response.isSuccessful)
                    someData.postValue(response.body()?.data)
    
                else
                    someData.postValue(emptyMap())
            }
    
            catch (e: Exception)
            {
                Log.e("ds error", e.message!!)
    
                someData.postValue(emptyMap())
            }
        }
    }
    
    fun getSomeData(): MutableLiveData<Map<String, String>>
    {
        return someData
    }
}

Everything works fine, but is there a way to get the same result without using the init? What if I need to run another API getter call? Should I just run another coroutine right below that 1st one? That seems inefficient.

2 Answers

You can create a function containing your coroutine and you can call it any number of times.

 class SomeApiRemoteSource (private var someApi: SomeApi)
    {
        private val someData = MutableLiveData<Map<String, String>>()
        private var apiJob: Job? = null
        
        init 
        {
            getDataFromAPI()
        }
        
        fun getDataFromAPI(){
         // Cancel previous job if already running
         apiJob?.cancel()
         apiJob = GlobalScope.launch(Dispatchers.IO)
            {
                try
                {
                    val response = someApi.getSomeData(SomeApi.API_KEY).awaitResponse()
        
                    if(response.isSuccessful)
                        someData.postValue(response.body()?.data)
        
                    else
                        someData.postValue(emptyMap())
                }
        
                catch (e: Exception)
                {
                    Log.e("ds error", e.message!!)
        
                    someData.postValue(emptyMap())
                }
            }
        }
        
        fun getSomeData(): MutableLiveData<Map<String, String>>
        {
            return someData
        }
    }

I got it. Took some inspiration from previous answers.

class FixerRemoteSource (private var fixerApi: FixerApi)
{
    suspend fun getAllSupportedSymbols(): Map<String, String>
    {
        val response = fixerApi.getAllSupportedSymbols(FixerApi.API_KEY)

        return if(response.isSuccessful) response.body()?.symbols!! else emptyMap()
    }
}

The problem that was blocking me was that the app kept crashing while I debugged the coroutine stuff. Removed the breaking points out of the coroutines and everything was fine.

Related