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.0.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!