Android Question Null Pointer error

Turbo3

Active Member
Licensed User
Longtime User
I just noticed that my released app is occasionally crashing for people with a null pointer error on one line of code.

B4X:
Dim BT_MacAdr As String    = "00:00:00:00:00:00"
...
Using_WiFi=Not((BT_MacAdr="") Or BT_MacAdr.contains(":") Or (BT_MacAdr="BTLE"))

The error would seem to indicate that "BT_MacAdr" has somehow become a null pointer. Looking at my code I see there is one place where I initialize "BT_MacAdr" with a previously saved value with this line of code:
B4X:
BT_MacAdr         = tr.ReadLine

My question is can the ReadLine fail in such a way that "BT_MacAdr" is set to a Null pointer value.

For example the file ends while trying to read that line or has data that can not be converted to a string. There is a Try Catch around the ReadLine code so any failure there would not crash the app.

I would expect that if there was any problem with the tr.ReadLine it would just set "BT_MacAdr" to an empty string not to a null pointer value which could cause a crash later in the app.

Actually, I don't understand how a string variable can ever be a null pointer. By default it should always be a null string (empty string) until assigned a value and so should never cause a null pointer crash of an app.

Here an example of the error message:
B4X:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference
 
Last edited:

ilan

Expert
Licensed User
Longtime User
a string default value should be NULL however in b4a it is ""

so if you would put: dim str as string and then log the string.length you would get 0 instead of an Error NullPointerException.
so if you are getting a NullPointerException it is probably the tr.ReadLine that throws it.
if you have a try catch around the readline code (as you wrote above) then when it fails set the BT_MacAdr = ""

like:

B4X:
Try
  BT_MacAdr = tr.ReadLine
Catch
  BT_MacAdr = ""
End Try

read this: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

Default Values
It's not always necessary to assign a value when a field is declared. Fields that are declared but not initialized will be set to a reasonable default by the compiler. Generally speaking, this default will be zero or null, depending on the data type. Relying on such default values, however, is generally considered bad programming style.

The following chart summarizes the default values for the above data types.

Data TypeDefault Value (for fields)
byte0
short0
int0
long0L
float0.0f
double0.0d
char'\u0000'
String (or any object) null
booleanfalse

Local variables are slightly different; the compiler never assigns a default value to an uninitialized local variable. If you cannot initialize your local variable where it is declared, make sure to assign it a value before you attempt to use it. Accessing an uninitialized local variable will result in a compile-time error.

acctualy when i make a simple test in b4j then i get a strange behavior instead of an java.lang.NullPointerException.

try this:
B4X:
    Dim str As String = Null
Log(str.Length)

and instead of getting an error i get 4. why do i get the length of the text NULL even i have not put it in brackets??

it seems like @Erel decided to catch like this a mistake by the programmer, or am i wrong? o_O
 
Upvote 0

Turbo3

Active Member
Licensed User
Longtime User
I have many Readline statements so I would like to know that that is the real source of the null pointer problem before I go and put a Try Catch around each and every one of them.

Actually I am switching over to using ReadList instead of the TextReader way of reading in a data file. Then there is just a single file.ReadList statement to fill up a list. I can then just check the length of the list to know what I got.

If a ReadLine statement can really set a string to a null pointer value it is something that needs to be avoided and would be a good reason to never use ReadLine.
 
Upvote 0

ilan

Expert
Licensed User
Longtime User
Actually I am switching over to using ReadList instead of the TextReader way of reading in a data file.

you could still use the textreader, you only need to check if the readline text is not NULL
i will show you 2 option how to avoid getting a NullPointerException

B4X:
Sub Activity_Create(FirstTime As Boolean)

'create text file
    Dim textwriter As TextWriter
    textwriter.Initialize(File.OpenOutput(File.DirInternal,"1.txt",False))
    For i = 0 To 10
        textwriter.WriteLine("line number: " & i)
    Next
    textwriter.Close
  
'read text from file  
    Dim all_lines, line As String
  
'read method 1
    Dim reader1 As TextReader
    reader1.Initialize(File.OpenInput(File.DirInternal,"1.txt"))
    all_lines = reader1.ReadAll

    log_all_lines(all_lines)
  
'read method 2
    all_lines = ""
    line = ""
  
    Dim reader2 As TextReader
    reader2.Initialize(File.OpenInput(File.DirInternal,"1.txt"))
    line = reader2.ReadLine
    Do While line <> Null
        all_lines = all_lines & CRLF & line
        line = reader2.ReadLine
    Loop
    reader2.Close
  
    log_all_lines(all_lines)
End Sub

Sub log_all_lines(all_lines As String)
  
    Log("#################################")
  
    Dim arr() As String = Regex.Split(CRLF,all_lines)
    For i = 0 To arr.Length -1
        Log(arr(i))
    Next
End Sub
 
Upvote 0

Turbo3

Active Member
Licensed User
Longtime User
Sorry, don't see how I would use that. What I am doing is reading in data to initialize variables which could be binary, int, float or strings. Here is a sample:
B4X:
BT_MacAdr      = tr.ReadLine
tmp                 = tr.ReadLine
pinBytes          =tmp.GetBytes("UTF8")
ScreenNum      = tr.ReadLine   
MileskWhr        = tr.ReadLine       
MxAvgMnTemp = tr.ReadLine       
ShowGidsPC     = tr.ReadLine       
ColorRadio       = tr.ReadLine
PassCode          = tr.ReadLine
 
Last edited:
Upvote 0

ilan

Expert
Licensed User
Longtime User
when you save the text file are you checking the variables?

what i understand from your last post you have a fix number of variables that you save to your text file you are later reading from.
so why are you getting a NULL Exception? you should get NULL Exception only if you try to read from the textfile and there are no more lines.

can you post the code where you save the textfile? (and maybe also the reading part, to see where is the problem)
 
Upvote 0

Turbo3

Active Member
Licensed User
Longtime User
Keep in mind this error happens only on a tiny number of users out of thousands.

As to why I am getting a NULL Exception on those hand full of users that is the question. Do they have limited storage so the write file failed to write all the data? Don't know. But if that is the case and the ReadLine had a problem and then assigned a Null Pointer to the String variable that would be the problem. The string was defined up until the ReadLine gave it a Null pointer. In this case I would have preferred B4A gave the string a Null value not a Null pointer. It makes debugging a released app a little harder when the problem crashes the app. Not to mention bad reviews.

I put a Try Catch around the Read file to prevent crashing the app if there was something wrong while reading the file. But that does not help if strings are assigned NULL pointers inside the Try part. The string was defined to start with and should have stayed that way under all conditions. If it can't be assigned a value give it a NULL value.

B4X:
tw.WriteLine(BT_MacAdr)
tw.WriteLine(Chr(pinBytes(0))&Chr(pinBytes(1))&Chr(pinBytes(2))&Chr(pinBytes(3)))
tw.WriteLine(ScreenNum)
tw.WriteLine(MileskWhr)
tw.WriteLine(MxAvgMnTemp)
tw.WriteLine(ShowGidsPC)   
tw.WriteLine(ColorRadio)
tw.WriteLine(PassCode)
 
Upvote 0

ilan

Expert
Licensed User
Longtime User
it could also be that when you save the variable it was already a NULL value. (but i dont think this is your problem)
what seems more logical for me is you are trying to read 8 lines to 8 variables but have only 7 lines (or less)

the reason for that could be that a variable was "" and if you try to writeline "" it wont write anythig to your text file and just skip to the next line

for example, i have 8 strings (or any other type that doesnot matter) and the string looks like this:

B4X:
    Dim str1 = "1", str2 = "2",str3 = "3",str4 = "4",str5 = "",str6 = "6",str7 = "",str8 = "8" As String

you can see the str5 and str7 are "" (so an empty string)
now when we would save all 8 strings to a textfile we would expect to read again 8 variables right??
well we wont get 8 variables the reason is, when we try to save str5 and str7 the writline process will skip those strings since they are empty
and we will get only 6 variables.

B4X:
Sub Activity_Create(FirstTime As Boolean)

'create text file
    Dim str1 = "1", str2 = "2",str3 = "3",str4 = "4",str5 = "",str6 = "6",str7 = "",str8 = "8" As String
    Dim textwriter As TextWriter
    textwriter.Initialize(File.OpenOutput(File.DirInternal,"1.txt",False))
    textwriter.WriteLine(str1)
    textwriter.WriteLine(str2)
    textwriter.WriteLine(str3)
    textwriter.WriteLine(str4)
    textwriter.WriteLine(str5)
    textwriter.WriteLine(str6)
    textwriter.WriteLine(str7)
    textwriter.WriteLine(str8)
    textwriter.Close
  
'read text from file  
    Dim all_lines As String
    Dim tr As TextReader
    tr.Initialize(File.OpenInput(File.DirInternal,"1.txt"))
    all_lines = tr.ReadAll
    log_all_lines(all_lines)
End Sub

Sub log_all_lines(all_lines As String)
    Dim arr() As String = Regex.Split(CRLF,all_lines)
    For i = 0 To arr.Length -1
        Log(arr(i))
    Next
End Sub

this is the log i get:
** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
1
2
3
4
6
8
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
** Service (starter) Destroy **

you can see i have only 6 lines and not 8 so what i am trying to say when you save your variables you must check that they are not blank ("") if the are
then change them to " " (put a space inside) otherwise you will have missing lines

what i believe is that in some devices they could not get all variables and instead they get a blank variable that was not written to the text file and thatshwy they had
a null exception.

so you need to make sure your variables are not blank, like:

B4X:
if BT_MacAdr = "" then BT_MacAdr = " "
 
Upvote 0

Turbo3

Active Member
Licensed User
Longtime User
The problem I see with that is that BT_MacAdr is the second variable read. So for it to be Null means all of the following writes also wrote an empty string which is just not the case. If BT_MacAdr was null when written it would have the value of the next variable when read back in which would be "1234" not a Null pointer.
 
Upvote 0

ilan

Expert
Licensed User
Longtime User
The problem I see with that is that BT_MacAdr is the second variable read. So for it to be Null means all of the following writes also wrote an empty string which is just not the case. If BT_MacAdr was null when written it would have the value of the next variable when read back in which would be "1234" not a Null pointer.

no, thats not correct, if BT_MacAdr was null you will get NULL back only if BT_MacAdr was empty like "" then the textwriter will skip it and not write that variable and you would have a missing line.

you can make a test, open a new blank b4a project copy the code from post #8 and change str1 = "1" to str1 = NULL

and the logs would be:

** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
null
2
3
4
6
8
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
** Service (starter) Destroy **

so you can see that a NULL variable is been saved to the textfile only a blank variable ("") is not been saved. (like you can see str5 and str7 is missing)
 
Upvote 0

Turbo3

Active Member
Licensed User
Longtime User
Ran the test. Works the way I think it should. Settings a string to Null is the same as assigning it the string "null". It does not make it a null pointer.

If I write an empty string "" then nothing is read back and BT_MacAdr would be assigned the next variable written that was not "".

So I don't see how anything I could do could cause this Null Pointer error.

Also you are wrong about the Textwriter. It has no problem writing out a blank string. It is the ReadLine that is at fault by not properly handing the empty string. Really B4x bug.
 
Last edited:
Upvote 0

Turbo3

Active Member
Licensed User
Longtime User
Erel,

Just to be clear, are you saying if I do a BT_MacAdr = TextReader.Readline past the end of the file the variable BT_MacAdr will be assigned a Null Pointer (not a Null string).
If it is assigned a Null Pointer that would explain the Null Pointer error and app crashing when the code tires to compare it to a string.

If it is assigned a Null string value then that does not explain the app crashing when BT_MacAdr is compared due to a Null Pointer error.
 
Upvote 0

Turbo3

Active Member
Licensed User
Longtime User
Erel, Thanks for the clarification. Yes I am switching over to the ReadList but this code is already released and I was trying to understand the source of the Null Pointer error on that line of code as reported to me by the Playstore crash reports. We are talking about some error condition here as the app only reads back what it writes out so under normal conditions this does not happen. But somehow a tiny number of users are seeing this Null Pointer error.

I will write a test app tomorrow to actually duplicate the Null Pointer crash and that should close this problem out.
 
Upvote 0

Turbo3

Active Member
Licensed User
Longtime User
Problem verified. Reading past the end of the file will not produce any error at that time but if you use any variable that was assigned a value past the end it will cause the Null Pointer error.

That makes using ReadLine very dangerous. You need to add a Null test for every string read in to see if you really got anything. You can not assume the file you wrote out is the same file you are reading back in and Try Catch does not help.

Definitely going to speed up the conversion of all the code to the ReadList method.
 
Upvote 0
Top