How to return boolean when using coroutines kotlin - kotlin

I get the error The boolean literal does not conform to the expected type Unit when run code. Please help me fix it
public suspend fun RequireDevice(manager: UsbManager, device: UsbDevice): UsbDevice? {
// 多重要求にならないようにする - Tránh nhiều yêu cầu
if(permissionContinuation != null)
return null
// requestPermissionを実行
val device = suspendCoroutine<UsbDevice?> {
manager.requestPermission(device, mPermissionIndent)
permissionContinuation = it
}
// continuationを消去
permissionContinuation = null
return device
}
function selectDevice
fun selectDevice(vendorId: Int, productId: Int): Boolean {
if ((mUsbDevice == null) || (mUsbDevice!!.vendorId != vendorId) || (mUsbDevice!!.productId != productId)) {
closeConnectionIfExists()
connectScope.launch label#{
val usbDevices: List<UsbDevice> = deviceList
for (usbDevice: UsbDevice in usbDevices) {
if ((usbDevice.vendorId == vendorId) && (usbDevice.productId == productId)) {
Log.v(LOG_TAG, "Request for device: vendor_id: " + usbDevice.vendorId + ", product_id: " + usbDevice.productId)
closeConnectionIfExists()
val grantedDevice = RequireDevice(mUSBManager!!, usbDevice)
if (grantedDevice != null){
Log.v(LOG_TAG, "Connected")
state = STATE_USB_CONNECTING
mHandler?.obtainMessage(STATE_USB_CONNECTING)?.sendToTarget()
return#label true
}
else{
Log.v(LOG_TAG, "Connection failed.")
return#label false
}
}
}
}
} else {
mHandler?.obtainMessage(state)?.sendToTarget()
return true
}
}
BroadcastReceiver
private val mUsbDeviceReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if ((ACTION_USB_PERMISSION == action)) {
synchronized(this) {
val usbDevice: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
Log.i(
LOG_TAG,
"Success get permission for device ${usbDevice?.deviceId}, vendor_id: ${usbDevice?.vendorId} product_id: ${usbDevice?.productId}"
)
mUsbDevice = usbDevice
openConnection()
permissionContinuation!!.resume(usbDevice)
state = STATE_USB_CONNECTED
mHandler?.obtainMessage(STATE_USB_CONNECTED)?.sendToTarget()
} else {
permissionContinuation!!.resume(null)
Toast.makeText(context, "User refused to give USB device permission: ${usbDevice?.deviceName}", Toast.LENGTH_LONG).show()
state = STATE_USB_NONE
mHandler?.obtainMessage(STATE_USB_NONE)?.sendToTarget()
}
}
} else if ((UsbManager.ACTION_USB_DEVICE_DETACHED == action)) {
if (mUsbDevice != null) {
Toast.makeText(context, "USB device has been turned off", Toast.LENGTH_LONG).show()
closeConnectionIfExists()
state = STATE_USB_NONE
mHandler?.obtainMessage(STATE_USB_NONE)?.sendToTarget()
}
} else if ((UsbManager.ACTION_USB_DEVICE_ATTACHED == action)) {
}
}
}
Error:
e:USBPrinterService.kt: (139, 42): The boolean literal does not conform to the expected type Unit
Error 2:
e:USBPrinterService.kt: (143, 42): The boolean literal does not conform to the expected type Unit
Error 3:
e:USBPrinterService.kt: (154, 5): A 'return' expression required in a function with a block body ('{...}')

The boolean literal does not conform to the expected type Unit
You're facing this error because the lambda passed to launch is not expected to return any useful value. Its return type is Unit, which is used in functions for which we don't expect any particular result, and you're trying to return a Boolean out of it, which doesn't match the return type.
In order to return a value, you would need to use async instead of launch. This way, the lambda can indeed return a value (here, a Boolean), and the async function itself will return a Deferred<Boolean> representing the future boolean value that will get when the task completes. However, there is a deeper problem here that you need to understand first.
You have to understand that this function signature denotes a synchronous function:
fun selectDevice(vendorId: Int, productId: Int): Boolean {
...
}
It means it blocks the calling thread until the result is returned, because it's not suspend and the Boolean value is returned directly (not via a callback or a Future or Deferred).
However, inside this function, you're trying to launch an asynchronous task (with the launch function), but you somehow still want to return the result from it. That's not how launch works. Because the task is asynchronous, the call to launch returns before the task is completed, and possibly even before the task starts at all. As we've also seen above, launch doesn't return any value itself. In fact, even if you change it to async, the async { .. } function call will not return the value directly, but a Deferred<Boolean> (as we've seen). This wrapper would be returned immediately (before the task completes or even starts), so you would then have to wait for this value to be ready somehow anyway.
Basically, with the signature you chose for selectDevice, you don't have a choice but to block the current thread until the value is ready, which kinda defeats the purpose of coroutines. Instead, it would be best if you made selectDevice a suspend function itself, so you can call suspend functions inside without launching new coroutines.
If you want to stick with the blocking signature, then you have to block the thread to wait for the value, for instance using runBlocking { deferred.await() }.

Related

Crash in coroutine

My function is quite straightforward,
Main Thread: Initializes a variable ->
Background Thread: Fire network request, assign the result back to the previous variable ->
Main Thread: Display that variable
Code below:
suspend fun createCity(context: Context, newCity: MutableLiveData<NewIdea>, mapBody: Map<String, String>, token: String) {
lateinit var response: NewIdea
try {
withContext(Dispatchers.IO) {
val map = generateRequestBody(mapBody)
response = webservice.createIdea(tripId, map, "Bearer $token")
getTrip(context, token)
}
} catch (e: Exception) {
Log.e(TAG, e.message)
}
newCity.value = response
}
But sometimes (it only happened 2 times actually) crashlytics reports crash for this line newCity.value = response
Fatal Exception: kotlin.UninitializedPropertyAccessException: lateinit property response has not been initialized
I don't really understand how that can happen.
Is this the correct way to return value from coroutine function?
thanks
Well if try block fails, it might happen that the lateinit variable isn't set at all. You should put the ui update code inside the try block as well, and handle the Exception separately:
Sidenote: withContext is well-optimized to return values, so you can make use of it.
suspend fun createCity(context: Context, newCity: MutableLiveData<NewIdea>, mapBody: Map<String, String>, token: String) {
try {
val response: NewIdea = withContext(Dispatchers.IO) {
val map = generateRequestBody(mapBody)
// does createIdea() first store it in var, then does getTrip(), then returns the result of createIdea() stored previously
webservice.createIdea(tripId, map, "Bearer $token").also { getTrip(context, token) } // ^withContext
}
newCity.value = response
} catch (e: Exception) {
Log.e(TAG, e.message)
}
}
A quick tip (optional): You can wrap the UI updating code with a withContext that dispatches the work to Dispatchers.Main when not running in main thread, while if running in main do nothing:
withContext(Dispatchers.Main.immediate) {
val response: NewIdea = withContext(Dispatchers.IO) {
val map = generateRequestBody(mapBody)
// does createIdea() first store it in var, then does getTrip(), then returns the result of createIdea() stored previously
webservice.createIdea(tripId, map, "Bearer $token").also { getTrip(context, token) } // ^withContext
}
newCity.value = response
}

Implement backoff strategy in flow

I'm trying to implement a backoff strategy just using kotlin flow.
I need to fetch data from timeA to timeB
result = dataBetween(timeA - timeB)
if the result is empty then I want to increase the end time window using exponential backoff
result = dataBetween(timeA - timeB + exponentialBackOffInDays)
I was following this article which is explaining how to approach this in rxjava2.
But got stuck at a point where flow does not have takeUntil operator yet.
You can see my implementation below.
fun main() {
runBlocking {
(0..8).asFlow()
.flatMapConcat { input ->
// To simulate a data source which fetches data based on a time-window start-date to end-date
// available with in that time frame.
flow {
println("Input: $input")
if (input < 5) {
emit(emptyList<String>())
} else { // After emitting this once the flow should complete
emit(listOf("Available"))
}
}.retryWhenThrow(DummyException(), predicate = {
it.isNotEmpty()
})
}.collect {
//println(it)
}
}
}
class DummyException : Exception("Collected size is empty")
private inline fun <T> Flow<T>.retryWhenThrow(
throwable: Throwable,
crossinline predicate: suspend (T) -> Boolean
): Flow<T> {
return flow {
collect { value ->
if (!predicate(value)) {
throw throwable // informing the upstream to keep emitting since the condition is met
}
println("Value: $value")
emit(value)
}
}.catch { e ->
if (e::class != throwable::class) throw e
}
}
It's working fine except even after the flow has a successful value the flow continue to collect till 8 from the upstream flow but ideally, it should have stopped when it reaches 5 itself.
Any help on how I should approach this would be helpful.
Maybe this does not match your exact setup but instead of calling collect, you might as well just use first{...} or firstOrNull{...}
This will automatically stop the upstream flows after an element has been found.
For example:
flowOf(0,0,3,10)
.flatMapConcat {
println("creating list with $it elements")
flow {
val listWithElementCount = MutableList(it){ "" } // just a list of n empty strings
emit(listWithElementCount)
}
}.first { it.isNotEmpty() }
On a side note, your problem sounds like a regular suspend function would be a better fit.
Something like
suspend fun getFirstNonEmptyList(initialFrom: Long, initialTo: Long): List<Any> {
var from = initialFrom
var to = initialTo
while (coroutineContext.isActive) {
val elements = getElementsInRange(from, to) // your "dataBetween"
if (elements.isNotEmpty()) return elements
val (newFrom, newTo) = nextBackoff(from, to)
from = newFrom
to = newTo
}
throw CancellationException()
}

Kotlin case of non-intuitive type inference

I found some non-intuitive behavior of type inference. As a result, the semantically equivalent code works differently, depending on what information the compiler infers about function return type. It is more or less clear what is going on when you reproduce this case in a minimum unit test. But I afraid that when writing framework code, such behavior could be dangerous.
The code below illustrates the problem, and my questions are:
Why the puzzler1 call from notok1 unconditionally throws NPE? As far as I understand from the bytecode, ACONST_NULL ATHROW throws NPE right after puzzler1 call, ignoring the returned value.
Is it normal that upper bound (<T : TestData>) is ignored when compiler infers the type?
Is it a bug that NPE becomes ClassCastException if you add suspend modifier to the function? Of course, I understand that runBlocking+suspend call gives us the different bytecode, but shouldn't the "coroutinized" code be as equivalent as possible to conventional code?
Is there a way to rewrite puzzler1 code somehow, eliminating the unclearness?
#Suppress("UnnecessaryVariable", "MemberVisibilityCanBePrivate", "UNCHECKED_CAST", "RedundantSuspendModifier")
class PuzzlerTest {
open class TestData(val value: String)
lateinit var whiteboxResult: TestData
fun <T : TestData> puzzler1(
resultWrapper: (String) -> T
): T {
val result = try {
resultWrapper("hello")
} catch (t: Throwable) {
TestData(t.message!!) as T
}
whiteboxResult = result
return result // will always return TestData type
}
// When the type of `puzzler1` is inferred to TestData, the code works as expected:
#Test
fun ok() {
val a = puzzler1 { TestData("$it world") }
// the same result inside `puzzler1` and outside of it:
assertEquals("hello world", whiteboxResult.value)
assertEquals("hello world", a.value)
}
// But when the type of `puzzler1` is not inferred to TestData, the result is rather unexpected.
// And compiler ignores the upper bound <T : TestData>:
#Test
fun notok1() {
val a = try {
puzzler1 { throw RuntimeException("goodbye") }
} catch (t: Throwable) {
t
}
assertEquals("goodbye", whiteboxResult.value)
assertTrue(a is NullPointerException) // this is strange
}
// The same code as above, but with enough information for the compiler to infer the type:
#Test
fun notok2() {
val a = puzzler1 {
#Suppress("ConstantConditionIf")
if (true)
throw RuntimeException("goodbye")
else {
// the type is inferred from here
TestData("unreachable")
// The same result if we write:
// puzzler1<TestData> { throw RuntimeException("goodbye") }
}
}
assertEquals("goodbye", whiteboxResult.value)
assertEquals("goodbye", (a as? TestData)?.value) // this is stranger
}
// Now create the `puzzler2` which only difference from `puzzler1` is `suspend` modifier:
suspend fun <T : TestData> puzzler2(
resultWrapper: (String) -> T
): T {
val result = try {
resultWrapper("hello")
} catch (t: Throwable) {
TestData(t.message!!) as T
}
whiteboxResult = result
return result
}
// Do exactly the same test as `notok1` and NullPointerException magically becomes ClassCastException:
#Test
fun notok3() = runBlocking {
val a = try {
puzzler2 { throw RuntimeException("goodbye") }
} catch (t: Throwable) {
t
}
assertEquals("goodbye", whiteboxResult.value)
assertTrue(a is ClassCastException) // change to coroutines and NullPointerException becomes ClassCastException
}
// The "fix" is the same as `notok2` by providing the compiler with info to infer `puzzler2` return type:
#Test
fun notok4() = runBlocking {
val a = try {
puzzler2<TestData> { throw RuntimeException("goodbye") }
// The same result if we write:
// puzzler2 {
// #Suppress("ConstantConditionIf")
// if (true)
// throw RuntimeException("goodbye")
// else
// TestData("unreachable")
// }
} catch (t: Throwable) {
t
}
assertEquals("goodbye", whiteboxResult.value)
assertEquals("goodbye", (a as? TestData)?.value)
}
}
What is the type of throw RuntimeException("goodbye")? Well, since it never returns a value, you can use it anywhere you like, no matter what type of object is expected, and it will always typecheck. We say that it has type Nothing. This type has no values, and it is a subtype of every type. Therefore, in notok1, you have a call to puzzler1<Nothing>. The cast from the constructed TestData to T = Nothing inside puzzler1<Nothing> is unsound but unchecked, and puzzler1 ends up returning when its type signature says it shouldn't be able to. notok1 notices that puzzler1 has returned when it said it would not be able to, and immediately throws an exception itself. It's not very descriptive, but I believe the reason it throws an NPE is because something has gone "terribly wrong" if a function that can't return has returned, so the language decides the program should die as fast as possible.
For notok2, you actually do get T = TestData: one branch of the if returns Nothing, the other TestData, and the LUB of those is TestData (since Nothing is a subtype of TestData). notok2 has no reason to believe that puzzler1<TestData> cannot return, so it doesn't set up the trap to die as soon as puzzler1 returns.
notok3 has essentially the same problem as notok1. The return type, Nothing, implies that the only thing the puzzler2<Nothing> will do is throw an exception. The coroutine handling code in notok3 thus expects the coroutine to hold a Throwable and contains code to rethrow it, but does not contain code to handle an actual return value. When puzzler2 actually does return, notok3 tries to cast that TestData into a Throwable and fails. notok4 works for the same reason notok2 does.
The solution to this mess is simply not using an unsound cast. Sometimes puzzler1<T>/puzzler2<T> will be able to return a T, if the passed function in fact returns a T. But, if that function throws, they can only return a TestData, and a TestData is not a T (a T is a TestData, not the other way around). The correct signature for puzzler1 (and similarly for puzzler2) is
fun <T : TestData> puzzler1(resultWrapper: (String) -> T): TestData
Since functions are covariant in the return type, you can just get rid of the type parameter
fun puzzler1(resultWrapper: (String) -> TestData): TestData

Kotlin: Multiple returns inside a Lambda

I have a function that catches recoverable exceptions and returns a fallback
private fun <T> safely(block: () -> T, fallback: T): T {
return try {
block()
} catch(exc: SomeException) {
// Log the exception/do some logic
fallback
}
}
I want to be able to add this to the public methods of my class e.g.
fun doSomething(): List<String> = safely({
val list = mutableListOf<String>("Hello")
fun someCheck1() = false // Some boolean value
fun someCheck2() = true // Some boolean value
do {
if(someCheck2()) {
return arrayListOf<String>("Hello", "World")
}
} while (someCheck1())
return list
}, arrayListOf<String>())
However I get compiler errors 'return' is not allowed here
Yet if I remove the return then my return in the loop no longer works and it gets highlighted in my IDE with warning the expression is never used
How can I maintain this type of return logic within a Lambda?
Playground Example
Try
fun doSomething(): List<String> = safely(
{
val list = mutableListOf<String>("Hello")
fun someCheck1() = false // Some boolean value
fun someCheck2() = true // Some boolean value
do {
if (someCheck2()) {
return#safely arrayListOf<String>("Hello", "World")
}
} while (someCheck1())
list
}
, arrayListOf<String>())
For further reference, check Using return inside a lambda?
Or you can also extract your block into a separate function (i.e. someCheckFunction(): List<String>), and have fun doSomething() = safely({ someCheckFunction() }, arrayListOf()), but I guess you want to maintain lambda code like above.
return arrayListOf<String>("Hello", "World") here tries to return a value from doSomething function rather than from the lambda passed to safely. However, such return is non-local, since it tries to exit from the function that is not on the top of stack, and therefore it is prohibited.
Another option here is to make safely function inline:
inline fun <T> safely(block: () -> T, fallback: T): T { ... }
and then you'll be able to make a non-local return from block lambda function passed to it.

Function returning Deferred with a name that does not end with async

I am trying to learn Kotlin coroutines recently I have noticed that in case of map that returns bunch of async IDE is displaying message saying that Function returning Deferred with a name that does not end with async. This is the code I have
runBlocking {
try {
val siteDeferred = async { getSite(order) }
// Place where I get warning-----------| (Function returning Deferred with a name that does not end with Async)
// v
val orderLineDeferred = order.line.map { async { getOrderDetail(it) } }
// Place where I get warning-------------------| (Function returning Deferred with a name that does not end with Async)
// v
val orderLineProductsDeferred = order.line.map { async { getOrderProductInformation(it.productId) } }
val site = siteDeferred.await()
val orderLine = orderLineDeferred.awaitAll()
val orderLineProducts = orderLineProductsDeferred.awaitAll()
} catch (e: Throwable) {
throw Exception(e.message)
}
}
private suspend getOrderDetail(OrderLine orderLine): OrderDetail...
private suspend getSite(Order order): Site ...
private suspend getOrderProductInformation(String productId): Product ...
Am I missing anything here. Furthermore, I would like to know whether this is the right way to do exception handling or not and is there a way to clean up try block so that I can get the value directly even if that means I will have to use async in other methods.
function getSite() renamed to getSiteAsync(),Others functions are modified in this way.