Migrate to Kotlin coroutines in Android with Kotlin 1.3

后端 未结 4 1257
温柔的废话
温柔的废话 2020-12-10 13:22

What should I change in my build.gradle file or import in classes to use stable coroutine functions in my Android project with Kotlin 1.3 ?

Fragment abo

4条回答
  •  夕颜
    夕颜 (楼主)
    2020-12-10 14:08

    In build.gradle change a library to

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

    Remove, if was added:

    kotlin {
        experimental {
            coroutines "enable"
        }
    }
    

    In code change launch to GlobalScope.launch(Dispatchers.IO) or GlobalScope.launch(Dispatchers.Main).

    UPDATE

    Please, use local coroutine context instead of global scope (see, for instance, http://kotlinlang.org/docs/reference/coroutines/coroutine-context-and-dispatchers.html).

    For Activity

    See https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md.

    Implement CoroutineScope:

    class YourActivity : AppCompatActivity(), CoroutineScope {
    

    Add a local variable job and initialize it:

    private lateinit var job: Job
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        job = Job()
    }
    

    Create a coroutine context and cancel it on Activity destroy:

    override fun onDestroy() {
        job.cancel()
        super.onDestroy()
    }
    
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job
    

    For Fragment (the same as in Activity)

    Implement CoroutineScope:

    class YourFragment : Fragment(), CoroutineScope {
    

    Create a local variable job and initialize it in onCreate(). (I tried to write private val job: Job = Job(), but bumped into problem that in ViewPager you will create Fragments and their jobs. As we will cancel the job in onDestroy() during swiping in ViewPager, we should recreate the job).

    private lateinit var job: Job
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        ...
        job = Job()
    }
    

    Create a coroutine context and cancel it on Fragment destroy:

    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Main + job // You can use different variants here. 
    
    override fun onDestroy() {
        job.cancel()
        super.onDestroy()
    }
    

    A launch example

    Use launch as usual:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        launch {
            // Wait for result of I/O operation without blocking the main thread.
            withContext(Dispatchers.IO) {
                interactor.getCountry().let {
                    countryName = it.name
                }
            }
    
            // Update views in the UI thread.
            country.updateCaption(countryName)
        }
    }
    

    In my case a problem occured when I used API requests with usual callbacks. A launch interior inside a callback hasn't been called. So I rewrote that code with interactors.

提交回复
热议问题