How can I know if a empty block is passed in Kotlin?

Viewed 104

I wish uriHandler.openUri(annotation.item) can be fired when I don't pass a block paramater to AnnotatedURLText, and block() can be fired when I pass one to it.

But I find uriHandler.openUri(annotation.item) isn't fired when I run Call A, B or C, how can I fire it?

Code 1

@Composable
fun AnnotatedURLText(
    ...   
    block: ()->Unit = {}
) {

   val uriHandler = LocalUriHandler.current
   ...

    ClickableText(
        ...
        onClick = { offset ->          
            annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset)
                .firstOrNull()?.let { annotation ->
                    if (block=={}) {
                        uriHandler.openUri(annotation.item)  //It can't be fired
                    }else{
                        block()
                    }
                }
        }
    )
}

Call A

AnnotatedURLText(...)
{
   todo()
}

Call B

AnnotatedURLText(...)

Call C

AnnotatedURLText(...)
{ 
}

Added Content

To Fogmeister: Thanks!

I write Code 2 based your ideas, but I get the following error.

@Composable invocations can only happen from the context of a @Composable function

Code 2

@Composable
fun AnnotatedURLText(
    ...   
    block: (String) -> Unit = {
        LocalUriHandler.current.openUri(it)  //It cause error
    }
) {
   ...

    ClickableText(
        ...
        onClick = { offset ->          
            annotatedText.getStringAnnotations(tag = "URL", start = offset, end = offset)
                .firstOrNull()?.let { annotation ->  
                    block(annotation.item)
                }
        }
    )
}
1 Answers

I don't think you can inspect the contents of the function you pass in like that. Instead of making the default value for that parameter {}, why not make it null instead?

fun AnnotatedURLText(
    ...   
    block: (() -> Unit)? = null
) {
    ...

    .firstOrNull()?.let { annotation ->
        // run block if it's not null, otherwise open the URI
        block?.invoke() ?: uriHandler.openUri(annotation.item)
    }

block.invoke() is the same as block(), but this way you can do the null-checking.

Don't think there's any way to stop people passing a block function that "does the wrong thing" though!


If your block function is meant to do something with that annotation.item (so its type is really (String) -> Unit) then you could possibly just use a reference to uriHandler.openUri as the default value:

fun AnnotatedURLText(
    ...   
    block: (String) -> Unit = LocalUriHandler.current::openUri
) {
    ...

    .firstOrNull()?.let { annotation ->
        // run block, whether it's the default or a user-provided function
        block(annotation.item)
    }

So basically instead of making a local uriHandler variable that points to whatever LocalUriHandler.current is, and then calling a function on that, we can just grab a direct reference to that function on that object, and use that as the default value for your function parameter. I'm assuming things about how your app is written but it should work!

Related