Android Question How to Raise and Propagate Exceptions with Known Messages

andrewj

Active Member
Licensed User
Longtime User
Hi,

I'm trying to find the best way of handling exceptions at different levels in a recursive structure. This is some cut-down sample code which includes the key problems:

B4X:
Sub Activity_Create(FirstTime As Boolean)
Try
    RecursiveCopy("A")
Catch
    Log(LastException.Message)
    If LastException.Message.Contains("Copying cancelled") Then
        Msgbox("Copy operation cancelled", "Confirmation")
    Else
        Msgbox(LastException.Message, "Error Occurred")
    End If
End Try
End Sub

Sub RecursiveCopy(sTarget As String)
Try
    Dim ex As ExceptionEx
   
    If sTarget.Length < 4 Then
        RecursiveCopy("B/" & sTarget)
    End If
    Log("Now processing: " & sTarget)
    If sTarget = "B/B/A" Then            ' We want to just skip this one, but carry on processing
        ex.Initialize("File Skipped")
        ex.Throw
    Else If sTarget = "B/A" Then        ' We want to cancel at this point, but return a meaningful exception
        ex.Initialize("Copying cancelled")
        ex.Throw
    End If

Catch
    If ex.IsInitialized Then
        If ex.Message = "File Skipped" Then
            Log("File copy skipped as requested")
        Else If ex.Message = "Copying cancelled" Then
            ex.Throw                    ' Re-raise for handling at next level
        End If
    Else If LastException.Message.Contains("Copying cancelled") Then
        ex.Initialize("Copying cancelled")
        ex.Throw                    ' Re-raise for handling at next level
    Else
        Msgbox(LastException.Message, "Error Occurred")
    End If
End Try
End Sub

This works, but I have to use a "Contains" check on the message at each level, and re-raise the exception using a new ExceptionEx object. I'd prefer to just be able to selectively either handle the exception locally (like with the "file skipped" case), or pass it back up the chain with a fixed message value.

Any ideas?
Thanks
Andrew
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Try to remove all the exception handling code and instead return a value from this sub that indicates what needs to be done:
B4X:
Sub RecursiveCopy(sTarget AsString)
 If sTarget.Length < 4 Then
        Dim res As Int = RecursiveCopy("B/" & sTarget)
        If res = 0 Then
           return 0
       Else if Res = 1 then
         'skip file or something like that..
      End If
    End If
 
Upvote 0

andrewj

Active Member
Licensed User
Longtime User
Hi Erel,
That won't do what I want. I want to trap a "cancel" which could be at any point in the stack, and stop processing. I was trying to avoid having to write explicit handling code for each condition all the way up the stack. I could do this, but in my real example it becomes very complex.

Is there no way to raise an exception as I am doing with the "Cancel" case and then make sure it retains it's message as it is passed up the stack?
Thanks
Andrew
 
Upvote 0

andrewj

Active Member
Licensed User
Longtime User
Thanks Erel.
My code above works in isolation. However in my larger project when I try and handle the exception a couple of layers up the stack I get the message "invocationTargetException" not "Copying cancelled". Any idea why?
Andrew
 
Upvote 0

andrewj

Active Member
Licensed User
Longtime User
Thanks. I've tried the following code, which ought to do what you're suggesting, but the second log fails because the "ex.Cause" returns null:
B4X:
ex = LastException
Log(ex.Message)
If ex.Message.Contains("InvocationTargetException") Then
    ex = ex.Cause
End If
Log(ex.Message)
Any ideas?
Thanks
Andrew
 
Upvote 0

andrewj

Active Member
Licensed User
Longtime User
Hi Erel,
Thanks for all your help. I've decided to go for a hybrid solution: I use exceptions where I want to break out of loops but swallow the event, like a single file skip, but I'm using a return value to pass more serious errors and cancel commands up the chain. This works fine.

It might be worth @agraham looking into why the inner exception is sometimes swallowed, but it's not critical.

BTW - V3.5 seems to run much quicker in debug mode than 3.2. Well done!

Andrew
 
Upvote 0
Top