'The withContext coroutine is not working. Using Kotlin in Android

I've been mulling this over for some time now and I just can't get it to work.

So in brief, I have a Splash Activity from where I call another activity that contains my ViewModel. The ViewModel in simple terms just needs to sequentially run function A(which is getfbdata below; it is a network call.). And only after this function completes, it should run function B (which is dosavefbdata below; save info to DB.). Again, it should wait for function B to complete before running the main thread function, function C(which is confirm first below; it checks whether function B has completed by getting the result from function B (dosavefbdata below). If function C is positive, it closes the Splash activity.

Suffice to say, none of the above works. Println results show all functions were run sequentially without waiting for each to complete. Lastly, SplashActivity().killActivity() call on function C did not work.

Note: withContext does not require to await() on the suspended functions right? I also tried using viewModelScope.async instead of viewModelScope.launch.

I would really appreciate your help here. Thanks in advance.


*Under SplashActivity:

fun killActivity(){
    finish()
}

*Under onCreate(SplashActivity):

CoroutingClassViewModel(myc).initialize() **


class CoroutingClassViewModel(val myc: Context): ViewModel() {

   fun initialize() {
        viewModelScope.launch(Dispatchers.Main) {
            try {
                val fbdata = withContext(Dispatchers.IO) { getfbdata() }
                val test1 = withContext(Dispatchers.IO) { test1(fbdata) }
                val savedfbdata = withContext(Dispatchers.IO) { dosavefbdata(fbdata,myc) }
                val confirmfirst = { confirmfunc(savedfbdata,myc) }
                println("ran savedfbdata.")
            } catch (exception: Exception) {
                Log.d(TAG, "$exception handled !")
            }
        }
    }   
    fun confirmfunc(savedfbdata: Boolean, myc: Context){
        if (savedfbdata==true){
            SplashActivity().killActivity()
        }
    }

    suspend fun getfbdata(): MutableList<FirebaseClass> {
        return withContext(Dispatchers.IO) {
            //perform network call
            return@withContext fbdata
        }
    }


    suspend fun dosavefbdata(fbdata: MutableList<FirebaseClass>,myc: Context): Boolean{
        return withContext(Dispatchers.IO) {
            //save to database
            return@withContext true
        }
    }

    suspend fun test1(fbdata: MutableList<FirebaseClass>){
        return withContext(Dispatchers.IO) {
            println("test1: fbdata is: $fbdata")
        }
    }
}


Solution 1:[1]

  • Use AndroidViewModel if you want to have Context in it:

    class CoroutingClassViewModel(myc: Application) : AndroidViewModel(myc) { ... }
    
  • In onCreate method of SplashActivity activity instantiate the view model like this:

    val vm = ViewModelProvider(this)[CoroutingClassViewModel::class.java]
    vm.initialize()
    
  • In CoroutingClassViewModel class create LiveData object to notify activity about operations completion:

    val completion = MutableLiveData<Boolean>()
    
    fun confirmfunc(savedfbdata: Boolean, myc: Context) {
        if (savedfbdata) {
            completion.postValue(true)
        }
    }
    

    In your SplashActivity use this code to observe completion:

    vm.completion.observe(this, Observer {
        if (it) killActivity()
    })
    
  • You use withContext(Dispatchers.IO) function two times for the same operation. Don't do that. For example in this code:

    val fbdata = withContext(Dispatchers.IO) { getfbdata() }
    

    if we look at getfbdata function we see that function withContext(Dispatchers.IO) is already called there. So get rid of repeated calls:

    val fbdata = getfbdata()
    

Solution 2:[2]

I had same issue with withContext(Dispatcher.IO), I thought that switching coroutine context doesn't work, while in fact in splash screen i launched super long operation on Dispatcher.IO, then later when trying to use the same Dispatcher.IO it didn't work or in other words it waited until the first work in splash screen finished then started the new work.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 BigSt
Solution 2 Amr