B4J Question TableView crashes after 100 refreshes

LDeeJay

Member
Lectori Salutem,

I've run into this oddity where a tableview crashes after it has been reloaded exactly 100 times. It's no use to do it in a loop, that doesn't refresh the table properly but when you click the button 100 times and let the table reload properly the app crashes (not joking).

I've reduced my code to the minimum and can reproduce it.

B4X:
#Region Project Attributes 
    #MainFormWidth: 600
    #MainFormHeight: 600 
#End Region

#AdditionalJar: sqlite-jdbc-3.7.2

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI 
    Private Button1 As B4XView
    Private TableView1 As TableView
    Private Label1 As Label
    Private sql As SQL
    Private counter As Int
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
    sql.InitializeSQLite(File.DirApp, "chinook.db", True)
End Sub

Sub Button1_Click
    counter = counter + 1    
    DBUtils.ExecuteTableView(sql, "SELECT artists.Name, albums.Title, tracks.Name FROM artists, albums, tracks WHERE albums.ArtistId = artists.ArtistId AND tracks.AlbumId = albums.AlbumId" , Null, 0, TableView1)
    Label1.Text = "Refreshed " & counter & " times."
End Sub

Sample with database is attached. I've no clue whether it's the sql connection or the tableview or DBUtils.

Hope someone can shed a light on this.

Cheers,

Leon

B4J 9.5
Java 11
DBUtils 2.11
 

Attachments

  • TestTableView.zip
    329.5 KB · Views: 22

LDeeJay

Member
I was afraid that would happen 😞
I think I can rule out the DBUtils. I've created a new module and put

B4X:
Public Sub ExecuteTableView3(SQL As SQL, Query As String, StringArgs() As String, Limit As Int, _
    TableView1 As TableView,instructions As Map)
    TableView1.Items.Clear
    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
    For i = 0 To cur.ColumnCount - 1
        cols.Add(cur.GetColumnName(i))
    Next
    TableView1.SetColumns(cols)
    Do While cur.NextRow
        Dim values(cur.ColumnCount) As Object
        For col = 0 To cur.ColumnCount - 1
            If instructions.ContainsKey(col) Then
                Dim instruction As String = instructions.Get(col)
              
                Select instruction.ToLowerCase
                    Case "checkbox"
                        Dim cb As CheckBox
                        cb.Initialize("twcb")
                      
                        If IsNumber(cur.GetString2(col)) Then
                            cb.Checked = cur.GetInt2(col) <> 0
                        Else
                            cb.Text = cur.GetString2(col)
                        End If
                        values(col) = cb
                End Select
            Else
                values(col) = cur.GetString2(col)
            End If
        Next
        TableView1.Items.Add(values)
        If Limit > 0 And TableView1.Items.Size >= Limit Then Exit
    Loop
    cur.Close
End Sub

Then I changed the TableView call to

B4X:
    Dim m As Map
    m.Initialize
    m.Put(0,"checkbox")
    myModule.ExecuteTableView3(sql, "SELECT artists.Name, albums.Title, tracks.Name FROM artists, albums, tracks WHERE albums.ArtistId = artists.ArtistId AND tracks.AlbumId = albums.AlbumId" , Null, 0, TableView1, m)

and it also crashes. Here's the crash log (forgot that one in the first post. Seems I have to try to get back to Java 8.....

B4X:
java.lang.NullPointerException
    at javafx.controls/javafx.scene.control.skin.TableCellSkin.tableColumnProperty(TableCellSkin.java:97)
    at javafx.controls/javafx.scene.control.skin.TableCellSkinBase.getTableColumn(TableCellSkinBase.java:123)
    at javafx.controls/javafx.scene.control.skin.TableCellSkinBase.dispose(TableCellSkinBase.java:136)
    at javafx.controls/javafx.scene.control.skin.TableCellSkin.dispose(TableCellSkin.java:88)
    at javafx.controls/javafx.scene.control.Control$2.invalidated(Control.java:267)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:147)
    at javafx.graphics/javafx.css.StyleableObjectProperty.set(StyleableObjectProperty.java:82)
    at javafx.controls/javafx.scene.control.Control$2.set(Control.java:250)
    at javafx.controls/javafx.scene.control.Control$2.set(Control.java:233)
    at javafx.controls/javafx.scene.control.Control.setSkin(Control.java:230)
    at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.recreateCells(TableRowSkinBase.java:715)
    at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.updateCells(TableRowSkinBase.java:505)
    at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.checkState(TableRowSkinBase.java:649)
    at javafx.controls/javafx.scene.control.skin.TableRowSkinBase.computePrefHeight(TableRowSkinBase.java:588)
    at javafx.controls/javafx.scene.control.Control.computePrefHeight(Control.java:570)
    at javafx.graphics/javafx.scene.Parent.prefHeight(Parent.java:1037)
    at javafx.graphics/javafx.scene.layout.Region.prefHeight(Region.java:1559)
    at javafx.controls/javafx.scene.control.skin.VirtualFlow.resizeCellSize(VirtualFlow.java:1863)
    at javafx.controls/javafx.scene.control.skin.VirtualFlow.addTrailingCells(VirtualFlow.java:2043)
    at javafx.controls/javafx.scene.control.skin.VirtualFlow.layoutChildren(VirtualFlow.java:1253)
    at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1204)
    at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1211)
    at javafx.graphics/javafx.scene.Parent.layout(Parent.java:1211)
    at javafx.graphics/javafx.scene.Scene.doLayoutPass(Scene.java:576)
    at javafx.graphics/javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2482)
    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)
 
Upvote 0

Magma

Well-Known Member
Licensed User
Longtime User
I think... somewhere... you must close the db/recordset... (i am not using dbutils... but i think will need that too)
checked that not needed to be closed...

but I think - it is because you are pressing/clicking too fast the button1...
for example if I put it in a loop with sleep(0) to just wait to get out from a command... i will get fast error (memory fail - because we are not waiting to .close the db... is asynchronous when pressing the button/the load of data).. .me getting error at 150~160 times...

but if give it.. for example 2000ms (this delay, may be need to change... if bigger db, more records) - will load anytime ok...

B4X:
Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
    sql.InitializeSQLite(File.DirApp, "chinook.db", True)
    For k=0 To 220
        Button1_Click
        Sleep(2000)
    Next
End Sub

Maybe you need to disable button when pressed... also give sometime with sleep(1500) and then enable button... so the end user not double clicking or playing with buttons...
 
Last edited:
Upvote 0

LDeeJay

Member
I've removed DBUtils and the issue stays....
I've just installed JDK8 and that solves the issue so I assume it's JDK11 that is the culprit....
I have not tested the combination of B4X 9.3 and JDK11 yet crashes as well so we (I) conclude it's JDK11...
 
Last edited:
Upvote 0

LDeeJay

Member
For k=0 To 220 Button1_Click Sleep(2000) Next
This saves you from clicking manually but does crash the app.
And clicking quickly prevents it from happening because the refresh doesn't take place properly. Are you using JDK11?
And in the original app I trigger the ExecuteTableView from the right-click context of the table itself, not a button. The sample I posted was a bare minimum from a clean project to reproduce the issue. It's definitely not the button clicking (speed).
 
Upvote 0

Magma

Well-Known Member
Licensed User
Longtime User
TableView is an old way for desktop only... b4xtable is a customview B4X (all platforms)... and ofcourse a better support... you can do many things.. (with some lines of code - also you have better control)
 
Upvote 0

Magma

Well-Known Member
Licensed User
Longtime User
This saves you from clicking manually but does crash the app.
And clicking quickly prevents it from happening because the refresh doesn't take place properly. Are you using JDK11?
And in the original app I trigger the ExecuteTableView from the right-click context of the table itself, not a button. The sample I posted was a bare minimum from a clean project to reproduce the issue. It's definitely not the button clicking (speed).
But if lower ms have error.. at 160 clicks

Using jdk 11.. latest b4j..9.50

Hmm strange 🤔
 
Upvote 0
Top