Andrew
Andrew

Reputation: 4712

Change try catch block to the function side

I would like to change my current try catch block to the function side. With my current implementation, I always have to write try catch and the calling side of my function, but I don't want this boilerplate code. This is my current implementation:

Function side

inline fun ActivityResult.checkResultAndExecute(block: ActivityResult.() -> Unit) {
    if (resultCode == Activity.RESULT_OK) this.block()
    else Timber.e("FrameworkUtils: Something went wrong on Registering a ActivityResult")
}

Call Side

result.checkResultAndExecute {
    try {
        val task = GoogleSignIn.getSignedInAccountFromIntent(data)
        val account = task.getResult(ApiException::class.java)
        loginViewModel.onEvent(LoginRegistrationEvent.SignInWithGoogle(account))
    } catch (e: Exception) {
        toast("Error")
    }
}

What I want is something like this (Current implementation):

inline fun ActivityResult.newCheckResultAndExecture(block: ActivityResult.(Exception?) -> Unit) {
    // Call function on ActivityResult. If an exception happens, then push it back to callin side
    try {
        this.block(null)
    } catch (e: Exception) {
        this.block(e)
    }
}

But I don't think that the way I wrote the new function is correct

Upvotes: 1

Views: 528

Answers (2)

Tenfour04
Tenfour04

Reputation: 93659

This seems like an error-prone way to handle errors. It's surprising that the same lambda handles both the try block and the catch block, and it's also surprising that the lambda is run twice when there's an error. There's a lot of room for using the function incorrectly.

You might consider using the standard library runCatching function to build something similar that is less error-prone:

inline fun <T> ActivityResult.runIfOkCatching(block: ActivityResult.() -> T): Result<T> =
    if (resultCode == Activity.RESULT_OK) runCatching(block)
    else Result.failure(Exception("FrameworkUtils: Something went wrong on Registering a ActivityResult"))

// At call site:
result.runIfOkCatching {
    val task = GoogleSignIn.getSignedInAccountFromIntent(data)
    val account = task.getResult(ApiException::class.java)
    loginViewModel.onEvent(LoginRegistrationEvent.SignInWithGoogle(account))
}.onFailure { e ->
    // Handle exception from running block or from resultCode not OK
}

Or if you don't want to treat a not-OK result as a failure, but simply log and do nothing:

inline fun ActivityResult.runIfOkCatching(block: ActivityResult.() -> Unit): Result<Unit> =
    if (resultCode == Activity.RESULT_FIRST_USER) {
        runCatching(block)
    } else {
        Timber.e("FrameworkUtils: Something went wrong on Registering a ActivityResult")
        Result.success(Unit)
    }

Upvotes: 1

Ircover
Ircover

Reputation: 2446

As I understand you just need to add error listener. If so you can use following code:

inline fun ActivityResult.checkResultAndExecture(block: ActivityResult.(Exception?) -> Unit, onErrorListener: ((Exception) -> Unit)? = null) {
    try {
        if (resultCode == Activity.RESULT_OK) this.block()
        else Timber.e("FrameworkUtils: Something went wrong on Registering a ActivityResult")
    } catch (e: Exception) {
        onErrorListener?.invoke(e)//in case of null listener is a bad approach
    }
}

I wrote simple solution with listener call, but it is not a best one, because with null listener you would miss exceptions. That can lead some unpleasant shadow error. Better at least to write them to log.

Upvotes: 1

Related Questions