I'm quite new to Kotlin coroutine and Android development in general. While playing around to understand how it worked, I faced an error I can't seem to solve.
From a basic activity i try to connect to the googleApiClient. The permissions are ok. I wish to use kotlin coroutines to get location updates from LocationManager in a direct style to use this Location object later on. The first time I changed my position in the emulator it works fine, the second time I change my position, It crashes with an exception like this:
FATAL EXCEPTION: main
Process: com.link_value.eventlv, PID: 32404
java.lang.IllegalStateException: Already resumed, but got value Location[gps 48.783000,2.516180 acc=20 et=+59m16s372ms alt=0.0 {Bundle[mParcelledData.dataSize=40]}]
at kotlinx.coroutines.experimental.AbstractContinuation.resumeImpl(AbstractContinuation.kt:79)
at kotlinx.coroutines.experimental.AbstractContinuation.resume(AbstractContinuation.kt:72)
at com.link_value.eventlv.View.Create.NewEventLvActivity$await$2$1.onLocationChanged(NewEventLvActivity.kt:100)
at android.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:297)
at android.location.LocationManager$ListenerTransport.-wrap0(LocationManager.java)
at android.location.LocationManager$ListenerTransport$1.handleMessage(LocationManager.java:242)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6077)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new_event_lv)
askForUserLocation()
val locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val presenter = CreateEventPresenterImpl(this@NewEventLvActivity)
googleApiClient = GoogleApiClient.Builder(this@NewEventLvActivity)
.enableAutoManage(this /* FragmentActivity */,
this /* OnConnectionFailedListener */)
.addApi(Places.GEO_DATA_API)
.addConnectionCallbacks(this)
.build()
}
override fun onConnected(p0: Bundle?) {
val locationManager = this.getSystemService(Context.LOCATION_SERVICE) as LocationManager
input_address.addTextChangedListener(object: TextWatcher{
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(query: CharSequence?, p1: Int, p2: Int, p3: Int) {
if (query.toString().length >= 4) {
launch(UI) {
val locationUpdated = locationManager.await(LocationManager.GPS_PROVIDER)
input_name.text = Editable.Factory.getInstance().newEditable(locationUpdated.toString())
}
}
}
})
}
private suspend fun LocationManager.await(locationProvider: String): Location? = suspendCoroutine { cont ->
try {
requestLocationUpdates(locationProvider, 0, 0.toFloat(), object : LocationListener {
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {
}
override fun onProviderEnabled(p0: String?) {
}
override fun onProviderDisabled(p0: String?) {
cont.resumeWithException(UnknownLocationException())
}
override fun onLocationChanged(location: Location?) {
cont.resume(location)
}
})
} catch (ex: SecurityException) {
cont.resumeWithException(ex)
}
}
It's as if Kotlin use the same Continuation. I don't know what I'm doing wrong and why it crashes the second time. Can someone enlighten me. Thks in advance.
To ignore any exceptions, launch the parent coroutine with the async function; however, if required to handle, the exception uses a try-catch block on the await() call on the Deferred object returned from async coroutine builder. When using launch builder the exception will be stored in a Job object.
This function throws a CancellationException if the Job of the coroutine is cancelled or completed while it is suspended. A typical use of this function is to suspend a coroutine while waiting for a result from a single-shot callback API and to return the result to the caller.
supervisorScopeThis function returns as soon as the given block and all its child coroutines are completed. Unlike coroutineScope, a failure of a child does not cause this scope to fail and does not affect its other children, so a custom policy for handling failures of its children can be implemented.
According to documentation, it's possible to resume Continuation only single time. Second resume will throw IllegalStateException
with "Already resumed, but got $proposedUpdate" message. You can add additional checking continuation.isActive
to prevent this exception. It's better to use Channels for multiple callbacks like location updates.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With