B4J Question Using Thread in B4J Application

swissmade

Well-Known Member
Licensed User
Hi all,

I wondering whats happening, when I initialize the same Thread again.
Is Java handling this as a new thread or is the Thread overwritten.
Or must I declare the Threads in a Array???

Also how can I get the Thread ID of the Running Thread.
Attached a small Test prog showing a Process Bar set value by 5 threads.
Thanks for Helping me out here.
 

Attachments

Last edited:

swissmade

Well-Known Member
Licensed User
There are several mistakes in your code. Remember that only the main thread is allowed to access UI elements.

In most cases it is a mistake to use the Threading library. Why do you need it?
In my Test program I see one mistage that I dont use RunOnGuiThread.
I need some Thread to avoid the UI to freeze in long Functions with some loops to read a resultset and do some checks.
This can be many Records and have to go without freezing the UI.
The Program has to keep running for new input from Users for a Access control system.
I try this with the threading Library because DOEvents not exist in Java.

I hope you can help me out here.
 

swissmade

Well-Known Member
Licensed User
The correct solution is:
1. Make sure that your SQL queries are optimized and that they use indices.
2. Use ExecQueryAsync to use a background thread and avoid freezing the UI.
The Querys are indices.
In some situations I can not make use of ExecQueryAsync because there has to be waited on the result.
 

swissmade

Well-Known Member
Licensed User
Optimized queries should be very fast.
Erel,
The reason the GUI freeze is the Update for a TableView.
I always test if something has changed if not we need no update.
All the Query's in this process take about 100ms what is fine and fast.

Update the TableView with InsertAT(0) take about 400-700ms.
I only Insert the records not exist in the Tableview.
This time is too long because there already new entry's waiting for access.

Maybe you have a idea how I can solve this.

Thanks for your help.
 

swissmade

Well-Known Member
Licensed User
How many items are you adding?

Have you tried to set all the items at once by setting TableView.Items = NewListOfItems ?
Hi Erel,

Somehow I can not get to your Page.
So I answer your questions this way.
There can be 1 but also 1000 items to add to the TableView.
If the Table is empty then all records from this day has to be shown in the TableView.
This is a access control system with RFID Tags, Fingerprint and Barcode readers.
I will try to first add the records to a list in memory and then if all is collected I add the items to the TableView and show them.

Many many thanks for your help.
 

jmon

Well-Known Member
Licensed User
The Querys are indices.
In some situations I can not make use of ExecQueryAsync because there has to be waited on the result.
What I do in cases like that is something similar to that:
B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
 
    'I create a map that holds the status of the queries:
    Private QueriesStatus As Map = CreateMap("Query1": False, "Query2": False, "Query3": False)
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Main") 'Load the layout file.
    MainForm.Show
 
    StartQueries
End Sub


Sub StartQueries
    Dim sq As SQL
    'Job 1
    sq.ExecQueryAsync("Query1", "SELECT * FROM customers;", Null)
    'Job 2
    sq.ExecQueryAsync("Query2", "SELECT * FROM countries;", Null)
    'Job 3
    sq.ExecQueryAsync("Query3", "SELECT * FROM planets;", Null)
End Sub

Sub Query1_QueryComplete (Success As Boolean, Crsr As ResultSet)
    If Success Then
        'Do my thing with this query
        '...
     
        'Save the status as true (finished):
        QueriesStatus.Put("Query1", True)
 
        'Then check the status of the other queries:
        CheckStatus     
    End If 
    sq.close
End Sub

Sub Query2_QueryComplete (Success As Boolean, Crsr As ResultSet)
    If Success Then
        '... something
        QueriesStatus.Put("Query2", True)
        CheckStatus     
    End If    
    sq.close  
End Sub

Sub Query3_QueryComplete (Success As Boolean, Crsr As ResultSet)
    If Success Then
        '... something
        QueriesStatus.Put("Query3", True)
        CheckStatus     
    End If  
    sq.close    
End Sub

Sub CheckStatus
    If QueriesStatus.Get("Query1") = True AND _
        QueriesStatus.Get("Query2") = True AND _
        QueriesStatus.Get("Query3") = True Then
     
        'All the queries are finished.
        '...
    End If 
End Sub
That way you get all 3 queries running together, and "CheckStatus" is only executed when they are all finished.

Edit:
By the way, what kind of controls do you have in your TV? In this test http://www.b4x.com/android/forum/threads/memory-leak.49751/#post-312592
I had 1000s of items refreshed in under 200ms
 
Last edited:

swissmade

Well-Known Member
Licensed User
What I do in cases like that is something similar to that:
Hi Jmon,
Very nice you think with me many thanks for this.
I use it already a similar way.
What I do is calling this Function every Time and Fetch the result in QueryComplete.
I also give the Query a TasID so I need one Function to fetch the Result.
The Checkstatus is a good idea.
See Code
B4X:
Public Sub StartQuery(strMYSQL As String, Task As Int)
Try
    If strMYSQL.Contains("SELECT") Then
        strMYSQL = strMYSQL.Replace("SELECT", "SELECT " & Task & " AS QueryID, ")
    End If
    If strMYSQL.Contains("COUNT") = False AND strMYSQL.Contains("SELECT") = True Then
        Functions.LastQuery = strMYSQL 'Check for Select Query
    End If 
    Functions.ConnectToUSERSCREEN
'*********************************************************************************** 
    Functions.SQLUSERSCREEN.ExecQueryAsync("SQLRespond", strMYSQL, Null)
'*********************************************************************************** 
Catch
    Functions.WriteErrorLog("Last error in StartQuery Main" & LastException.Message )
End Try
End Sub
 
Last edited:
Top