Android Question [SOLVED] NullPointerException on LastException

Alessandro71

Well-Known Member
Licensed User
Longtime User
I'm getting NullPointerException crash reports from the Play Console like this:

java.lang.NullPointerException:
at anywheresoftware.b4a.keywords.Common.LastException (Common.java:810)
at priusfan.info.bthsd10.main._vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv5 (main.java:3918)
at priusfan.info.bthsd10.main._statustimer_tick (main.java:4704)
at java.lang.reflect.Method.invoke (Native Method)
at anywheresoftware.b4a.BA.raiseEvent2 (BA.java:186)
at anywheresoftware.b4a.objects.Timer$TickTack.run (Timer.java:105)
at android.os.Handler.handleCallback (Handler.java:751)
at android.os.Handler.dispatchMessage (Handler.java:95)
at android.os.Looper.loop (Looper.java:154)
at android.app.ActivityThread.main (ActivityThread.java:6692)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1358)

since I'm using code obfuscation, the vvvvv... label equals to this sub:

B4X:
Private Sub RefreshStatusLine
    Try
'various code
    Catch
        Private last = LastException As Exception
        util.HandleException("Main.RefreshStatusLine", last, util.EXCEPTION_RECOVERABLE)
    End Try
End Sub

as far as I understand, the exception is caused by LastException itself in the Catch branch
How can I deal with such a case?
 

Computersmith64

Well-Known Member
Licensed User
Longtime User
Although the way you declare "last" seems to work in code, I would probably change it to:

B4X:
    Private last as Exception = LastException

Also, creating a variable to assign LastException to & then pass to your util.HandleException seems somewhat redundant. Why don't you just pass LastException? Eg:

B4X:
    util.HandleException("Main.RefreshStatusLine", LastException, util.EXCEPTION_RECOVERABLE)

- Colin.
 
Upvote 0

Alessandro71

Well-Known Member
Licensed User
Longtime User
Also, creating a variable to assign LastException to & then pass to your util.HandleException seems somewhat redundant. Why don't you just pass LastException? Eg:

B4X:
    util.HandleException("Main.RefreshStatusLine", LastException, util.EXCEPTION_RECOVERABLE)

Original code was as you suggested.
I changed it to the "redundant" version to test behavior, with no different outcome.
 
Upvote 0

Alessandro71

Well-Known Member
Licensed User
Longtime User
Both patterns are fine.

Can you post the code inside the Try block?

Here is full code.
But be aware that I have the same exception error on other subs also.
The Try block is clearly failing, but the Catch block should not.

B4X:
Private Sub RefreshStatusLine
    Try
        If (scanner.Status = scanner.STATUS_STOPPED) Then    'show status from main activity
                Select Status
                   
                    Case STATUS_IDLE
                        updatstatus(Starter.loc.Localize("main_updstat_idle"), Colors.Yellow)
                       
                    Case STATUS_NOTCONNECTED
                        updatstatus(Starter.loc.Localize("main_notconnected_not_connected"), Colors.Red)
                       
                    Case STATUS_CONNECTING
                        updatstatus(Starter.loc.Localize("main_updstat_connecting"), Colors.Yellow)

                    Case Else
                        Logger.WriteDebugLog("Unexpected Main Status " & Status)
                End Select

        Else    'scanner status has precedence
                Select scanner.Status

                    Case scanner.STATUS_STARTED
                        updatstatus(Starter.loc.Localize("main_updstat_service_started"), Colors.Yellow)
                       
                    Case scanner.STATUS_INITSEQUENCE
                        updatstatus(Starter.loc.Localize("scanner_init"), Colors.Magenta)
           
                    Case scanner.STATUS_CONNECTEDTOCAR
                        updatstatus(CarStatus.car.GetCarFamilyName, Colors.Green)
           
                    Case scanner.STATUS_WAITING
                        updatstatus(Starter.loc.Localize("scanner_decode_wait_car"), Colors.Magenta)
           
                    Case scanner.STATUS_CONNECTIONLOST
                        updatstatus(Starter.loc.Localize("scanner_tmr_connection_lost"), Colors.Red)
               
                    Case Else
                        Logger.WriteDebugLog("Unexpected Scanner Status " & scanner.Status)
                End Select
               
        End If
    Catch
        Private last = LastException As Exception
        util.HandleException("Main.RefreshStatusLine", last, util.EXCEPTION_RECOVERABLE)
    End Try
End Sub
 
Upvote 0

Alessandro71

Well-Known Member
Licensed User
Longtime User
just in case...

B4X:
public Sub updatstatus(text As String, color As Int)
    Try
        Lbl_connect.Text=text
        Lbl_connect.Color=color
    Catch
        Private last = LastException As Exception
        util.HandleException("Main.updatstatus", last, util.EXCEPTION_RECOVERABLE)
    End Try
End Sub
 
Upvote 0

Alessandro71

Well-Known Member
Licensed User
Longtime User
This code is running inside Main activity
The same Catch block structure (obviously with different Try code) seems to work fine in a Service module
Also, just to make not so easy, I'm unable to reproduce issue on my test devices: I just receive crash reports on Play Console, but I'm not able to trigger it at will.
 
Upvote 0

Alessandro71

Well-Known Member
Licensed User
Longtime User
no luck
since RefreshStatusLine is called by a timer tick event, I checked the paused state before calling it (both are inside the Main module)

B4X:
Sub StatusTimer_Tick
    If (IsPaused(Me)) Then
        Return
    End If

    RefreshStatusLine
    RefreshSettingsButton
End Sub

but still I have this exception, fresh from Play Console

java.lang.NullPointerException:
at anywheresoftware.b4a.keywords.Common.LastException (Common.java:810)
at priusfan.info.bthsd10.main._vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv2 (main.java:3985)
at priusfan.info.bthsd10.main._statustimer_tick (main.java:4776)
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
You should stop timers from activity when entering activity_pause
You can start them again (when needed) in Activity_resume

OR use a Service for the timer and check if you need to start a/the activity.
 
Upvote 0

Alessandro71

Well-Known Member
Licensed User
Longtime User
Yes, timer is a global variable, and I added try/catch only in the tick event.
But beside that, is it expected to get an exception in LastException?
Shouldn’t it just return an empty exception if one is not available?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Upvote 0

Alessandro71

Well-Known Member
Licensed User
Longtime User
as a followup for those interested:
after i surrounded LastException with a try/catch block, null pointer exception reports from the Play Console went away

as a matter of fact, all exceptions seem to come from activity Subs called from a service by CallSub.
event if all CallSub calls were testing if the activity was paused

B4X:
If Not(IsPaused(Main)) Then
    CallSub(Main, "GenericSubCalledByCallSub")
End If

and every sub was again testing its state

B4X:
Sub GenericSubCalledByCallSub
    If (IsPaused(Me)) Then
        Return
    End If

    Try
        'some code
    Catch
        util.HandleException("GenericSub", EXCEPTION_CRITICAL)
    End Try
End Sub

it was not until i modified exception handling this way:

B4X:
Public Sub HandleException(subName As String, critical As Boolean)
    Private last As Exception
    Private validException = False As Boolean
    Try
        last = LastException
        validException = True
    Catch
        Logger.WriteDebugLog("HandleException from " & subName)
    End Try
  
    If (validException) Then
        If (last.IsInitialized) Then
            Logger.WriteDebugLog(subName & ": " & last)
          
            If (critical) Then
                Starter.CR.GenerateReport(last, "This is an exception from " & subName)
            End If
        End If
    End If
End Sub
forgive my approximate answer
it's declared as Private in the Process_Globals section of the Main activity
 
Upvote 0
Top