How to migrate Kotlin from 1.2 to Kotlin 1.3.0 then using async, UI, and bg in a presenter function

Viewed 4430

I am using MVP pattern on a Kotlin Project. I have a Presenter class:

import com.google.gson.Gson
import kotlinx.coroutines.experimental.android.UI
import kotlinx.coroutines.experimental.async
import org.jetbrains.anko.coroutines.experimental.bg

class TeamsPresenter(private val view: TeamsView,
                     private val apiRepository: ApiRepository,
                     private val gson: Gson
) {
    fun getTeamList(league: String?) {
        view.showLoading()

        async(UI){
            val data = bg {
                gson.fromJson(apiRepository
                    .doRequest(TheSportDBApi.getTeams(league)),
                    TeamResponse::class.java
                )
            }
            view.showTeamList(data.await().teams)
            view.hideLoading()
        }
    }   
}

this presenter class working fine on Kotlin 1.2.71, but I can't get it working on Kotlin 1.3.0.

I updated Kotlin version in project's build.gradle, removed "experimental coroutines" and added kotlin coroutine core dependency:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0'

and this is my current code:

import com.google.gson.Gson

class TeamsPresenter(private val view: TeamsView,
                     private val apiRepository: ApiRepository,
                     private val gson: Gson
) {
    fun getTeamList(league: String?) {
        view.showLoading()

        async(UI){
            val data = bg {
                gson.fromJson(apiRepository
                    .doRequest(TheSportDBApi.getTeams(league)),
                    TeamResponse::class.java
                )
            }
            view.showTeamList(data.await().teams)
            view.hideLoading()
        }
    }
}

Error mainly on async, UI, and bg function:

unresolved reference: async
unresolved reference: UI
unresolved reference: bg

How can I get this to work on Kotlin 1.3.0? for any help, thanks in advance.

3 Answers

you must use GlobalScope.launch instead of launch ,GlobalScope.async instead of async Dispatcher.main instead of UI

coroutineBasics

Your code has several layers of problems:

  1. You're using async, but you don't await on it. You should be using launch instead.
  2. You're using the pre-coroutines facility of bg, equivalent to async
  3. You immediately await on bg, which means you should be using withContext(Default) instead
  4. (new with Kotlin 1.3) You aren't applying structured concurrency

This is how your code should look in Kotlin 1.3:

fun CoroutineScope.getTeamList(league: String?) {
    view.showLoading()
    this.launch {
        val data = withContext(Dispatchers.IO) {
            gson.fromJson(apiRepository.doRequest(TheSportDBApi.getTeams(league)),
                    TeamResponse::class.java
            )
        }
        view.showTeamList(data.teams)
        view.hideLoading()
    }
}

You should call your function with the coroutine scope appropriate to your situation. A typical approach is tying it to your activity:

class MyActivity : AppCompatActivity(), CoroutineScope {
    lateinit var masterJob: Job
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + masterJob

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        masterJob = Job()
    }

    override fun onDestroy() {
        super.onDestroy()
        masterJob.cancel()
    }
}

Also add

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'

Here is a fix ( I don't know if it is the best way to do it) :

import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch

class TeamsPresenter(private val view: TeamsView,
                     private val apiRepository: ApiRepository,
                     private val gson: Gson
) {
    fun getTeamList(league: String?) {
        view.showLoading()
        CoroutineScope(Dispatchers.Main).launch {
            val data = async {
                gson.fromJson(apiRepository
                    .doRequest(TheSportDBApi.getTeams(league)),
                    TeamResponse::class.java
                )
            }
            view.showTeamList(data.await().teams)
            view.hideLoading()
        }
    }
}
Related