B4J Question [SOLVED]Reloading tableview constantly causes crash on Tableview

Peter Lewis

Active Member
Licensed User
Hi All

I have a very simple application which monitors a MySQL table on a server within my private network. All it does go through 20 records from one file searching how many times it appears in another table and then puts the result back into the first table. This works well. Then I display it in a tableview.

I have a timed loop thereafter reloading and recalculating the table every 10 seconds.

This is the first time i have tried B4X instead of the B4J tableview.

My problem happens after about 10 minutes of doing this. I have the debug screen and I see all the calculations are done (They continue) and 1 error appears which I trapped and the loading of the B4X tableview just stops. I am running 50% load of memory on my machine and 62% CPU load.

The Table view is now unresponsive and I cannot click on it to make a row selected but the column sort does click but does not work even on the existing data in the table..

I put a counter on the reload and it loaded 101 times before not loading anymore.

This is the error I get when it stops loading the data
java.lang.NullPointerException
at javafx.controls/javafx.scene.control.skin.CellSkinBase.access$100(CellSkinBase.java:56)
at javafx.controls/javafx.scene.control.skin.CellSkinBase$StyleableProperties$1.isSettable(CellSkinBase.java:166)
at javafx.controls/javafx.scene.control.skin.CellSkinBase$StyleableProperties$1.isSettable(CellSkinBase.java:161)
at javafx.graphics/javafx.scene.CssStyleHelper.transitionToState(CssStyleHelper.java:666)
at javafx.graphics/javafx.scene.Node.doProcessCSS(Node.java:9647)
at javafx.graphics/javafx.scene.Node.access$900(Node.java:398)
at javafx.graphics/javafx.scene.Node$1.doProcessCSS(Node.java:471)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSSImpl(NodeHelper.java:192)
at javafx.graphics/com.sun.javafx.scene.ParentHelper.superProcessCSSImpl(ParentHelper.java:93)
at javafx.graphics/com.sun.javafx.scene.ParentHelper.superProcessCSS(ParentHelper.java:63)
at javafx.graphics/javafx.scene.Parent.doProcessCSS(Parent.java:1366)
at javafx.graphics/javafx.scene.Parent.access$400(Parent.java:79)
at javafx.graphics/javafx.scene.Parent$1.doProcessCSS(Parent.java:125)
at javafx.graphics/com.sun.javafx.scene.ParentHelper.processCSSImpl(ParentHelper.java:98)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.superProcessCSSImpl(ControlHelper.java:63)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.superProcessCSS(ControlHelper.java:55)
at javafx.controls/javafx.scene.control.Control.doProcessCSS(Control.java:886)
at javafx.controls/javafx.scene.control.Control.access$000(Control.java:83)
at javafx.controls/javafx.scene.control.Control$1.doProcessCSS(Control.java:89)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.processCSSImpl(ControlHelper.java:67)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:145)
at javafx.graphics/javafx.scene.Parent.doProcessCSS(Parent.java:1397)
at javafx.graphics/javafx.scene.Parent.access$400(Parent.java:79)
at javafx.graphics/javafx.scene.Parent$1.doProcessCSS(Parent.java:125)
at javafx.graphics/com.sun.javafx.scene.ParentHelper.processCSSImpl(ParentHelper.java:98)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.superProcessCSSImpl(ControlHelper.java:63)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.superProcessCSS(ControlHelper.java:55)
at javafx.controls/javafx.scene.control.Control.doProcessCSS(Control.java:886)
at javafx.controls/javafx.scene.control.Control.access$000(Control.java:83)
at javafx.controls/javafx.scene.control.Control$1.doProcessCSS(Control.java:89)
at javafx.controls/com.sun.javafx.scene.control.ControlHelper.processCSSImpl(ControlHelper.java:67)
at javafx.graphics/com.sun.javafx.scene.NodeHelper.processCSS(NodeHelper.java:145)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9529)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9522)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9522)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9522)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9522)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9522)
at javafx.graphics/javafx.scene.Node.processCSS(Node.java:9522)
at javafx.graphics/javafx.scene.Scene.doCSSPass(Scene.java:569)
at javafx.graphics/javafx.scene.Scene.access$3400(Scene.java:172)
at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2477)
at javafx.graphics/com.sun.javafx.tk.Toolkit.lambda$runPulse$2(Toolkit.java:412)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:411)
at javafx.graphics/com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:438)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:519)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:499)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.pulseFromQueue(QuantumToolkit.java:492)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$11(QuantumToolkit.java:320)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:834)

Any ideas , Thank you
 
Last edited:

Harris

Expert
Licensed User
Longtime User
Need your code.
How are you accessing the table with MySQL. Did you close the query? Are you using a pool?

Hard to tell from the log...
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
Sometimes you just need a nudge.... This is a common mistake and now - you will never forget to check....
 
Upvote 0

Peter Lewis

Active Member
Licensed User
Sometimes you just need a nudge.... This is a common mistake and now - you will never forget to check....
Seems like that was not the problem. It still crashes

This is the only sub that runs code apart from the timer and the initial sup that loads the layout and start the timer and this sub

B4X:
    Dim Cursor As JdbcResultSet
    Cursor = sql2.ExecQuery("SELECT WebsiteAddr, TimesDisplayed FROM adverts")
    Do While Cursor.NextRow
        Dim pq As String
        pq=Cursor.GetString("WebsiteAddr")
        
        Log(pq)
        
            Dim NumberOfMatches As Int

        NumberOfMatches=sql2.ExecQuerySingleResult2("Select count(*) FROM advertinfo WHERE `Advert` LIKE ? ",Array As String(pq))
                    
        Log(NumberOfMatches)
        
        Dim updatefields As Map
    
        updatefields.Initialize
        updatefields.Put("TimesDisplayed",NumberOfMatches)
        
        Dim WhereFields As Map
        WhereFields.Initialize
        WhereFields.Put("WebsiteAddr",pq)
    
        sql2.ExecNonQuery2("Update adverts SET TimesDisplayed = ? WHERE WebsiteAddr = ?",Array (NumberOfMatches,pq.Trim))
        
        
    Loop

    DBUtils.ExecuteTableView(sql2,"Select WebsiteAddr, TimesDisplayed from adverts",Null,0,TableView1)
    RefreshCount= RefreshCount+1
    Lrefresh.Text=RefreshCount
    Cursor.Close
 
Upvote 0

DarkoT

Active Member
Licensed User
Hi,

just from my experience - based on Db knowledge...
Try to update manually in MySql Db:

Update adverts SET TimesDisplayed = 102 WHERE WebsiteAddr = "xxxxx"

If this working, then you need to check what is with array (NumberOfMatches may be presented as string!!)

DaRko
 
Upvote 0

OliverA

Expert
Licensed User
This is the first time i have tried B4X instead of the B4J tableview.
Huh? I only see "standard" TableView usage
DBUtils.ExecuteTableView(sql2,"Select WebsiteAddr, TimesDisplayed from adverts",Null,0,TableView1)
This
java.lang.NullPointerException
at javafx.controls/javafx.scene.control.skin.CellSkinBase.access$100(CellSkinBase.java:56)
Seems to be more like an issue with the TableView then with the data retrieval. As written, that code (the data retrieval code) is all blocking and therefore could affect your UI, but I don't know if that is an issue (with a local network as data access).
 
Upvote 0

Peter Lewis

Active Member
Licensed User
Hi,

just from my experience - based on Db knowledge...
Try to update manually in MySql Db:

Update adverts SET TimesDisplayed = 102 WHERE WebsiteAddr = "xxxxx"

If this working, then you need to check what is with array (NumberOfMatches may be presented as string!!)

DaRko
Thank you for you input.

I took out all of the Sub that dealt with accessing the DB so the only code that was left was the code that wrote to the tableview and it crashed but this time after 119 times

I tried your suggestion and that also crashed at 101 times.

I do not know if it is a Memory issue loading so many times, maybe something in Java

Thank you
 
Upvote 0

Peter Lewis

Active Member
Licensed User
Huh? I only see "standard" TableView usage

This

Seems to be more like an issue with the TableView then with the data retrieval. As written, that code (the data retrieval code) is all blocking and therefore could affect your UI, but I don't know if that is an issue (with a local network as data access).

ok let me research the B4X tutorial. I thought that in the designer all i had to do was to choose
1588856040487.png

Dim Tableview1 as B4XView and use that in the code. Obviously now you mention it ,that is not all
 
Upvote 0

DarkoT

Active Member
Licensed User
Thank you for you input.

I took out all of the Sub that dealt with accessing the DB so the only code that was left was the code that wrote to the tableview and it crashed but this time after 119 times

I tried your suggestion and that also crashed at 101 times.

I do not know if it is a Memory issue loading so many times, maybe something in Java

Thank you

Peter,
Maybe I know where can be problem... In same routine you READ data from same table, as you update the table...
I think, you need to work with some local variable in Do While - Loop and count NumberOfMatches... And on the End, outside from Do While Loop routine, after you closing the Cursor, you need to update table... Try...

Regards, Darko
 
Upvote 0

OliverA

Expert
Licensed User
Peter,
Maybe I know where can be problem... In same routine you READ data from same table, as you update the table...
That should not be an issue. The same (as of now) with all the db access being done by non-asynchronous methods. Peter did the right thing and just tried the
B4X:
    DBUtils.ExecuteTableView(sql2,"Select WebsiteAddr, TimesDisplayed from adverts",Null,0,TableView1)
without anything else (at least that is how I read his statement:
I took out all of the Sub that dealt with accessing the DB so the only code that was left was the code that wrote to the tableview and it crashed but this time after 119 times
) and it still crashes. So something is up with using TableView in this scenario.
 
Upvote 0

OliverA

Expert
Licensed User
Try this:
In the same class/module as the code above, declare the following global variable:
B4X:
Private sqlViews As Map
Add this sub to the same class/module
B4X:
Public Sub ExecuteTableView2(SQL As SQL, Query As String, StringArgs() As String, Limit As Int, _
    TableView1 As TableView)
    TableView1.Items.Clear
    If Not(sqlViews.IsInitialized) Then sqlViews.Initialize
    Dim cur As ResultSet
    If StringArgs = Null Then
        Dim StringArgs(0) As String
    End If
    cur = SQL.ExecQuery2(Query, StringArgs)
    Dim cols As List
    cols.Initialize
    If Not(sqlViews.ContainsKey(TableView1)) Then
        Log("ExecuteTableView2 called the first time for this TableView")
        For i = 0 To cur.ColumnCount - 1
            cols.Add(cur.GetColumnName(i))
        Next
        TableView1.SetColumns(cols)
        sqlViews.Put(TableView1, Query) ' Query value just a filler (for now)
    Else
        Log("ExecuteTableView2 previously called on this TableView. Skipping SetColumns")
    End If
    Do While cur.NextRow
        Dim values(cur.ColumnCount) As String
        For col = 0 To cur.ColumnCount - 1
            values(col) = cur.GetString2(col)
        Next
        TableView1.Items.Add(values)
        If Limit > 0 And TableView1.Items.Size >= Limit Then Exit
    Loop
    cur.Close
End Sub
Replace
B4X:
DBUtils.ExecuteTableView(sql2,"Select WebsiteAddr, TimesDisplayed from adverts",Null,0,TableView1)
with
B4X:
ExecuteTableView2(sql2,"Select WebsiteAddr, TimesDisplayed from adverts",Null,0,TableView1)
Note: All this does is not create the headers constantly (it only creates them on the first call). No clue if this helps (you'll have to try). The Query passed needs to be the same for a given TableView (the main query, the StringArgs are ok to change).
 
Upvote 0

Peter Lewis

Active Member
Licensed User
Try this:
In the same class/module as the code above, declare the following global variable:
B4X:
Private sqlViews As Map
Add this sub to the same class/module
B4X:
Public Sub ExecuteTableView2(SQL As SQL, Query As String, StringArgs() As String, Limit As Int, _
    TableView1 As TableView)
    TableView1.Items.Clear
    If Not(sqlViews.IsInitialized) Then sqlViews.Initialize
    Dim cur As ResultSet
    If StringArgs = Null Then
        Dim StringArgs(0) As String
    End If
    cur = SQL.ExecQuery2(Query, StringArgs)
    Dim cols As List
    cols.Initialize
    If Not(sqlViews.ContainsKey(TableView1)) Then
        Log("ExecuteTableView2 called the first time for this TableView")
        For i = 0 To cur.ColumnCount - 1
            cols.Add(cur.GetColumnName(i))
        Next
        TableView1.SetColumns(cols)
        sqlViews.Put(TableView1, Query) ' Query value just a filler (for now)
    Else
        Log("ExecuteTableView2 previously called on this TableView. Skipping SetColumns")
    End If
    Do While cur.NextRow
        Dim values(cur.ColumnCount) As String
        For col = 0 To cur.ColumnCount - 1
            values(col) = cur.GetString2(col)
        Next
        TableView1.Items.Add(values)
        If Limit > 0 And TableView1.Items.Size >= Limit Then Exit
    Loop
    cur.Close
End Sub
Replace
B4X:
DBUtils.ExecuteTableView(sql2,"Select WebsiteAddr, TimesDisplayed from adverts",Null,0,TableView1)
with
B4X:
ExecuteTableView2(sql2,"Select WebsiteAddr, TimesDisplayed from adverts",Null,0,TableView1)
Note: All this does is not create the headers constantly (it only creates them on the first call). No clue if this helps (you'll have to try). The Query passed needs to be the same for a given TableView (the main query, the StringArgs are ok to change).
Yes it is giving me an error saying I cannot hide global variable names, so i presume they are already declared in the SQL lib
 
Upvote 0

OliverA

Expert
Licensed User
Change it to another name (both in global and in the sub), such as sqlViewsMap or something.
 
Upvote 0

Peter Lewis

Active Member
Licensed User
Try this:
In the same class/module as the code above, declare the following global variable:
B4X:
Private sqlViews As Map
Add this sub to the same class/module
B4X:
Public Sub ExecuteTableView2(SQL As SQL, Query As String, StringArgs() As String, Limit As Int, _
    TableView1 As TableView)
    TableView1.Items.Clear
    If Not(sqlViews.IsInitialized) Then sqlViews.Initialize
    Dim cur As ResultSet
    If StringArgs = Null Then
        Dim StringArgs(0) As String
    End If
    cur = SQL.ExecQuery2(Query, StringArgs)
    Dim cols As List
    cols.Initialize
    If Not(sqlViews.ContainsKey(TableView1)) Then
        Log("ExecuteTableView2 called the first time for this TableView")
        For i = 0 To cur.ColumnCount - 1
            cols.Add(cur.GetColumnName(i))
        Next
        TableView1.SetColumns(cols)
        sqlViews.Put(TableView1, Query) ' Query value just a filler (for now)
    Else
        Log("ExecuteTableView2 previously called on this TableView. Skipping SetColumns")
    End If
    Do While cur.NextRow
        Dim values(cur.ColumnCount) As String
        For col = 0 To cur.ColumnCount - 1
            values(col) = cur.GetString2(col)
        Next
        TableView1.Items.Add(values)
        If Limit > 0 And TableView1.Items.Size >= Limit Then Exit
    Loop
    cur.Close
End Sub
Replace
B4X:
DBUtils.ExecuteTableView(sql2,"Select WebsiteAddr, TimesDisplayed from adverts",Null,0,TableView1)
with
B4X:
ExecuteTableView2(sql2,"Select WebsiteAddr, TimesDisplayed from adverts",Null,0,TableView1)
Note: All this does is not create the headers constantly (it only creates them on the first call). No clue if this helps (you'll have to try). The Query passed needs to be the same for a given TableView (the main query, the StringArgs are ok to change).


Yes, this is working perfectly I did over 400 re-reads and no problem yet.

What is the reasoning for the problem so I can learn for the future ? So it was just the header which was the issue


THANK YOU
 
Upvote 0

OliverA

Expert
Licensed User
What is the reasoning for the problem so I can learn for the future ?
1) Your error message posting. Googling for
at javafx.controls/javafx.scene.control.skin.CellSkinBase.access$100(CellSkinBase.java:56)
led me to this posting at https://bugs.openjdk.java.net/browse/JDK-8210545. The posting did not contain an answer (that would have been too easy), but pointed me in the direction of the TableView being the issue
2) You posted that you took out everything but the displaying of the TableView. You still had the same issue, therefore strengthening the link between TableView and the issue you are experiencing.
3) Looking at the code for DBUtils' ExecuteTablveView I was trying to figure out what part of that code could be causing issues for your particular case. I noticed that every call to that method set the column headers. Could that be an issue? Not knowing the answer, I wrote up the code above to test the theory/guess that setting a TableView's column headers is causing your issues. Looks like I got lucky.
 
Upvote 0

Peter Lewis

Active Member
Licensed User
1) Your error message posting. Googling for led me to this posting at https://bugs.openjdk.java.net/browse/JDK-8210545. The posting did not contain an answer (that would have been too easy), but pointed me in the direction of the TableView being the issue
2) You posted that you took out everything but the displaying of the TableView. You still had the same issue, therefore strengthening the link between TableView and the issue you are experiencing.
3) Looking at the code for DBUtils' ExecuteTablveView I was trying to figure out what part of that code could be causing issues for your particular case. I noticed that every call to that method set the column headers. Could that be an issue? Not knowing the answer, I wrote up the code above to test the theory/guess that setting a TableView's column headers is causing your issues. Looks like I got lucky.
Thank you for taking the time and effort to solve this problem. Now i can see the methodology of what you used I can apply that to problems in the future. Too many times i have just been given the solution which does not help me learn and in future help other people.

Thank you, Once again
 
Upvote 0
Top