Seems incompatible with release version 1.0.1 of Kotlin coroutines library

I’m trying to work my way through this chapter, and the listings won’t compile properly because the experimental coroutines library is deprecated and the release version (org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1) is subtly incompatible with the listings as written.

Example: listing 22.7 won’t work because the release definition of “async” is not compatible with the lambda provided here - and I’m too inexpert to understand exactly why.

After poking around (quite a bit) with the Kotlin 1.0.1 documentation, I came up with the following, which seems to work correctly. Feedback appreciated!

generateButton.setOnClickListener {
GlobalScope.launch( Dispatchers.Main ) … }

and

fun fetchCharacterData(): Deferred<CharacterGenerator.CharacterData> {
return GlobalScope.async { … }

Incidentally, if the network is for some reason unavailable (I turned on airplane mode to see what would happen), the app crashes because the URL.readText() call throws a fatal exception. In a production setting this would have to be dealt with.

3 Likes

With the release of Kotlin 1.3, coroutines are no longer experimental. You are correct on the migration from the experimental version to the release version.

To your second point about network connectivity, it is somewhat beyond the scope of this book to solve the problem. But borrowing from BNR Android Programming, a solution to do so is below. This builds off my solution posted in Challenge: Live Data

The following helper function checks the network state

private fun isNetworkAvailableAndConnected(): Boolean {
    val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    return cm.activeNetworkInfo?.isConnected ?: false
}

Then inside of onCreate(), we can choose how to handle network connectivity

characterData = savedInstanceState?.characterData ?: let {
        if( isNetworkAvailableAndConnected() ) {
            fetchCharacterFromAPI()
            CharacterGenerator.placeHolderCharacter()
        } else {
            Toast.makeText(baseContext, "Turn on network connectivity for characters of lore", Toast.LENGTH_SHORT).show()
            CharacterGenerator.generate()
        }
    }

Finally, I chose to override the onResume() callback to turn the generate button on/off

override fun onResume() {
    super.onResume()
    generateButton.isEnabled = isNetworkAvailableAndConnected()
}
1 Like