Android Question null pointer exception - but where???

RichyK68

Active Member
Licensed User
Longtime User
Hi,

I'm writing a game that uses JPCT and it's virtually impossible to run it in legacy/rapid debug mode without it erroring, due to threads, so I'm having to test in release mode.

I am getting a null pointer exception somewhere in the following code. I've put toast messages in to try to track where it is happening, but something is causing it to jump to the Catch method. The key to the BoardCellList is a string in the format of number dash number, the value is a structure of type CellInfo. When Ci is assigned I test the field Vanished which is a boolean.

Can anybody give me a lead as to why it could be giving a null pointer exception? It gets most of the way through the list of 225 items in BoardCellList before erroring. For each indexed item in the list I get the key to the item, I test if it's null, it's not else I'd see the "key is null" toast. Then using the key I get the actual value of type CellInfo. I test the value that is returned for null, and don't do anything if it's null, but if it's not null I test Vanished flag, and then add to a string variable.

B4X:
            Try
                Dim vanished2 As String = ""
                Dim key As Object = Null
                For loop1 = 0 To GameState.BoardCellList.Size - 1
                    last = loop1
                    key = GameState.BoardCellList.GetKeyAt(loop1)
                    If key <> Null Then
                        Dim ci As CellInfo = GameState.BoardCellList.get(key)
                        If ci <> Null Then
                            If ci.vanished Then 
                                If vanished2.length > 0 Then vanished2 = vanished2 & ","
                                vanished2 = vanished2 & key
                            End If
                        End If
                    Else
                        ToastMessageShow("key is null", False)
                    End If
                Next
            Catch
                ToastMessageShow("debug: vanished ... " & LastException.Message & " @ " & last & "/" & (GameState.BoardCellList.Size-1), True)
            End Try


Thanks,

Richard
 

RichyK68

Active Member
Licensed User
Longtime User
The string variable vanished2 will contain something if ci.vanished = true as it then does

B4X:
If vanished2.length > 0Then vanished2 = vanished2 & ","
vanished2 = vanished2 & key

It'll build up a string like "1-1,1-2,1-3" etc as the key to the list is a string like "1-2".

All IFs/End Ifs match :)

Richard
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
B4X:
If key <> Null Then
  Dim ci As CellInfo = GameState.BoardCellList.get(key)
  If ci <> Null Then
    If ci.vanished Then
      If vanished2.length > 0 Then
        vanished2 = vanished2 & ","
      end if ' <<-- THIS end if is missing in your code...
      vanished2 = vanished2 & key
    End If
  End If
Else
  ToastMessageShow("key is null", False)
End If
 
Upvote 0

JTmartins

Active Member
Licensed User
Longtime User
As DonManfred has pointed there is a missing End If and if you have the same in your IDE, then the app shouldn't compile.
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
There is no End If missing.

This is valid without the End If
If vanished2.length > 0 Then vanished2 = vanished2 & ","
Personally I don't like it but it is valid.

A missing End If generates a
Error description: Missing Keyword: end if
Occurred on line: xx
End Sub
error message in the End Sub line.
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
Klaus is correct. You can write an If like:

B4X:
If x = y Then z = 0

Or even:

B4X:
If x = y Then z = 0 Else z = 1

You could also write:

B4X:
If x = y Then z = 0 : x = 1

in which case the "x = 1" will get executed after the If statement, regardless of the result. Same with:

B4X:
If s.Length > 0 Then s = "Not Empty" Else s = "Empty" : Msgbox(s, "Test")

As for what's causing the null pointer, I'm not sure (or why it's not being caught in your Try... Catch... End Try) - but if you can't run in debug mode, perhaps you could log each loop to a text file & you might get a better idea of where the issue is. Maybe something in your BoardCellList is not being initialized?

Btw - I don't think you will ever see the "key is null" Toast message because if your key is Null, you will get a null pointer exception at your "If key <> Null" statement - but it should get caught in your exception handler. Your app will still crash, but you should see your "debug:..." Toast message.

- Colin
 
Upvote 0

RichyK68

Active Member
Licensed User
Longtime User
I suspect, but haven't proved it yet, that it is threading related. The code provided runs on the Click event of a button, but the contents of the list is enumerated and modified in the background thread of a JPCT surface draw event. This thread doesn't add or remove items, simply gets an item, changes it, puts it back. I think this is what is causing it.
 
Upvote 0

RichyK68

Active Member
Licensed User
Longtime User
Is there an equivalent of VB. Net's Sync Lock in B4A? I know this question was asked in another thread (no pun intended) but it was never answered. I have a background thread (the JPCT surface draw) referencing the same structures in a list as my button click event. In VB, a simple Sync Lock in those two places would solve the clash (if this is what is occurring here) simply. Is there an alternative here?
 
Upvote 0

eps

Expert
Licensed User
Longtime User
Put some logs in and log all the values being assigned, before they are assigned.. Then check the log and if it's always failing at the same point, you should be able to work out why it's failing.

and as for this...

B4X:
If vanished2.length > 0Then vanished2 = vanished2 & ","
vanished2 = vanished2 & key

It would help to write it a bit more like this

B4X:
If vanished2.length > 0Then vanished2 = vanished2 & ","
       vanished2 = vanished2 & key

It makes it easier to read, apologies if it's the browser reformat trick that made it less readable.
 
Upvote 0

eps

Expert
Licensed User
Longtime User
B4X:
Try
     Dim vanished2 AsString = ""
     Dim key AsObject = Null
     For loop1 = 0 To GameState.BoardCellList.Size - 1
        last = loop1
log("key "+ key)
        key = GameState.BoardCellList.GetKeyAt(loop1)
        If key <> Null Then
           Dim ci As CellInfo = GameState.BoardCellList.get(key)
log("ci "+ ci)
           If ci <> Null Then
                  If ci.vanished Then
                             If vanished2.length > 0Then vanished2 = vanished2 & ","
log("vanished2 "+ vanished2)
                                      vanished2 = vanished2 & key
                  EndIf
          EndIf
       Else
           ToastMessageShow("key is null", False)
       EndIf
     Next
CatchToastMessageShow("debug: vanished ... " & LastException.Message & " @ " & last & "/" & (GameState.BoardCellList.Size-1), True)
EndTry

or something like that..
 
Upvote 0

Computersmith64

Well-Known Member
Licensed User
Longtime User
B4X:
If vanished2.length > 0Then vanished2 = vanished2 & ","
vanished2 = vanished2 & key

It would help to write it a bit more like this

B4X:
If vanished2.length > 0Then vanished2 = vanished2 & ","
       vanished2 = vanished2 & key

It makes it easier to read, apologies if it's the browser reformat trick that made it less readable.[/quote]

Why would you indent a line that is not part of the previous If statement? It's already indented correctly relative to the If statement that it's part of. Indenting it again makes it more difficult to read because it makes it look like it's part of an If statement that it has no relationship to.

Just my 2c worth coming from having always written single line If statements that way from way back in the VB days. It makes no sense to me to write:

B4X:
If a=b Then c=a

this way:

B4X:
If a=b Then
    c=a
End If

It doesn't make it any more readable & just adds a redundant End If.

- Colin.
 
Upvote 0

JTmartins

Active Member
Licensed User
Longtime User
Well, I do apologize then for the IF / End IF thing. I was not aware of that in B4A.

you have to log it then, as debug won't help much with JPCT.

Try to Check all the itens in the Map.
 
Upvote 0

eps

Expert
Licensed User
Longtime User
B4X:
If vanished2.length > 0Then vanished2 = vanished2 & ","
vanished2 = vanished2 & key

It would help to write it a bit more like this

B4X:
If vanished2.length > 0Then vanished2 = vanished2 & ","
       vanished2 = vanished2 & key

It makes it easier to read, apologies if it's the browser reformat trick that made it less readable.

Why would you indent a line that is not part of the previous If statement? It's already indented correctly relative to the If statement that it's part of. Indenting it again makes it more difficult to read because it makes it look like it's part of an If statement that it has no relationship to.

Just my 2c worth coming from having always written single line If statements that way from way back in the VB days. It makes no sense to me to write:

B4X:
If a=b Then c=a

this way:

B4X:
If a=b Then
    c=a
End If

It doesn't make it any more readable & just adds a redundant End If.

- Colin.[/quote]

Hi Colin

I didn't say to add an End If, but to indent the statement that is not at the same level as the If statement itself. Of course layout of code is a highly subjective thing!! :) It's the way I like to lay the code out, but of course others may disagree - although in this case, if it had been indented it would have made it obvious that the If statement was correctly formed.. but anyway!
 
Upvote 0

RichyK68

Active Member
Licensed User
Longtime User
Hi all,

It is threading related, as I fixed it by setting a flag to true in the gui click event, and waiting in a loop for the flag to be set to false. In the surface draw thread, which fires 30 to 60 times a second, it checks to see if the flag is set to true, if it is it does the building up of the vanished2 variable, and sets the flag to false. The gui event then exits the loop and uses this variable. The problem went away. My guess is when the surface draw event goes through the boardcelllist, and does a get and put on each item, the gui thread just has the misfortune of accessing the data between the get and the put, and I think the item is temporarily unavailable for that brief moment.

It's now manifesting itself in a different spot as I loop through the list, but it's at random positions in the list each time. I know for a fact the list has 225 items in there, all initialized, but sometimes it fails at item 38, sometimes at 208.

I really need a Sync Lock equivalent to allow access to the list by one thread at time. Is there an equivalent technique I can use?

Richard
 
Upvote 0

eps

Expert
Licensed User
Longtime User
Are you able to sketch this out and show what you think is happening and what you expect to happen. I usually find a piece of paper and a pencil or pen really helps in these situations. Either something will become obvious from that exercise or you can at least post what you are attempting to achieve and someone might be able to help.

This might help? http://www.b4x.com/android/forum/threads/threading-library.6775/
 
Upvote 0

RichyK68

Active Member
Licensed User
Longtime User
I fixed both issues with a BoardCellListLock.Wait in the GUI thread and the surface draw event. Now one thread has to wait for the other to finish its work with the List and they are both happy campers. No pen & paper required :)

Richard
 
  • Like
Reactions: eps
Upvote 0
Top