简体   繁体   中英

Migrate to Kotlin coroutines in Android with Kotlin 1.3

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 about coroutines in my build.gradle

implementation "org.jetbrains.kotlin:kotlin-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlin:kotlin-coroutines-android:$coroutines_version"

Of course I use Android Studio 3.3 Preview

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 Fragment s 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.

My teammate helped me to find the solution. I had to increase the coroutines version to 1.0.0-RC1. For everyone who may don't know about the changes in using Android coroutines:

  • I had to change the UI context of coroutine to Dispatchers.Main
  • I used old experimental coroutines version (0.23 maybe) so for everyone who don't know - now launch is deprecated and you should use structured concurrency (for example coroutineScope ) instead.
  • Now async function cannot be run outside the scope.

I hope I will help someone. Don't waste a time. Happy programming!

The implementation version must be >= the testing version

build.gradle (:mobile)

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines")

    // Testing
    testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
    androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
}

build.gradle (Project)

buildscript {
    ...
    ext.coroutines = '1.3.6'
}

FAILURE FIXED

FAILURE: Build failed with an exception.

* What went wrong:
Could not determine the dependencies of task ':app:processDebugAndroidTestManifest'.
> Could not resolve all task dependencies for configuration ':app:debugAndroidTestRuntimeClasspath'.
    > Could not resolve org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5.
    Required by:
        project :app
     > Cannot find a version of 'org.jetbrains.kotlinx:kotlinx-coroutines-core' that satisfies the version constraints:
          Dependency path 'Open Weather:app:unspecified' --> 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5'

GL

Simply add "mavenCentral()" to build.gradle bellow build script: I fixed using this.

buildscript {
    ext.kotlin_version = '1.3.72'

    repositories {
        google()
        jcenter()

    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.0.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        mavenCentral() //Add this Line only <<<<<<<<<<<<<<<<<<
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM