B4i Library Background Task - Run a Sub in background thread without blocking the UI (Asynchronous)

narek adonts

Well-Known Member
Licensed User
Hi All,

UPDATED - You can add Parameters (maximum 2) to your task
(You can also add as many variable as you need with declaring them as global variables. So you can use them in your BG sub)

UPDATED 2 - You can return a result to Sub_Done event. See Example below.

------------------------------------------------------------------------------------------------

Run a Sub in Background thread (without blocking the UI).


1. Add the class attached to your project

2.

Example without Parameter

B4X:
Dim myBGTask As BackgroundTask

myBGTask.Initialize("MyTask",Me,Array(Null))

Sub MyTask

    'Do your background staff

    'NO UI

End Sub

Sub MyTask_Done

    'Background Task Finished

    'Update your UI

End Sub
Example with 1 Parameter

B4X:
Dim myBGTask As BackgroundTask

myBGTask.Initialize("MyTask",Me,Array(yourParam))

Sub MyTask(Param as string/...)

    'Do your background staff

    'NO UI

End Sub

Sub MyTask_Done

    'Background Task Finished

    'Update your UI

End Sub
Example with 2 Paramters

B4X:
Dim myBGTask As BackgroundTask

myBGTask.Initialize("MyTask",Me,Array(Param1, Param2))

Sub MyTask(Param1 as String, Param2 as Float)

    'Do your background staff

    'NO UI

End Sub

Sub MyTask_Done

    'Background Task Finished

    'Update your UI

End Sub
Example with returning a Result to the main process

B4X:
Dim myBGTask As BackgroundTask

myBGTask.Initialize("MyTask",Me,Array(Null))

Sub MyTask

    'Do your background staff

    'NO UI

    myBGTask.Result= YourResult

End Sub

Sub MyTask_Done (Result)

    'Background Task Finished

    'Update your UI

End Sub

ATTENTION !!! Do not forget that you can not change the UI in the Background Sub. You have to Update the UI in Sub_Done event or after.
 

Attachments

Last edited:

joop

Active Member
Licensed User
Hi, narek I tried your class for my problem , loop blocking main thread when reading
and writing big array,see the project file.

The labels can only be cleared after the complete loop is finished,then the UI reacts
on the buttonevent , the labels can not be cleared in between the 4 loops but
maybe you'r solution is not for this problem ? (no errors by the way)
 

Attachments

narek adonts

Well-Known Member
Licensed User
Hi, narek I tried your class for my problem , loop blocking main thread when reading
and writing big array,see the project file.

The labels can only be cleared after the complete loop is finished,then the UI reacts
on the buttonevent , the labels can not be cleared in between the 4 loops but
maybe you'r solution is not for this problem ? (no errors by the way)

You should not update the UI in background thread (label1.text=...)

The background tast is starting when you initializing it.

try this

B4X:
Sub Button1_Click
Dim myBGTask As BackgroundTask

myBGTask.Initialize("loop1",Me)
End Sub

Sub loop1

Dim size As Int = 800000
Dim value As Int
For j= 0 To size
        value = testarray1(j)
        testarray2(j) =value
     Next
     If DateTime.Now > lastPreviewSaved + 100 Then 'shouldn't block main tread ?
      lastPreviewSaved = DateTime.Now               ' so change button2.txt ?
     End If

loop2
End Sub


Sub loop2

Dim size As Int = 800000
Dim value As Int
For j= 0 To size
        value = testarray1(j)
        testarray2(j) =value
     Next
     If DateTime.Now > lastPreviewSaved + 100 Then
      lastPreviewSaved = DateTime.Now 
     End If

loop3
          
End Sub

Sub loop3

Dim size As Int = 800000
Dim value As Int
For j= 0 To size
        value = testarray1(j)
        testarray2(j) =value
     Next
     If DateTime.Now > lastPreviewSaved + 100 Then
      lastPreviewSaved = DateTime.Now 
     End If
loop4         
End Sub

Sub loop4

Dim size As Int = 800000
Dim value As Int
For j= 0 To size
        value = testarray1(j)
        testarray2(j) =value
     Next
     If DateTime.Now > lastPreviewSaved + 100 Then
      lastPreviewSaved = DateTime.Now 
     End If    
End Sub
 

joop

Active Member
Licensed User
Thanks a lot narek ! , it works ok in the release mode.

Global declarations of the two very large arrays to show that it works :

B4X:
Private testarray1 (8000000) As Byte
Private testarray2 (8000000) As Byte
B4X:
Sub Button1_Click
   Label1.Text=""       ' clear the label 
   Dim myBGTask As BackgroundTask
   myBGTask.Initialize("loop1",Me)
End Sub

Sub Button2_Click   
   Label1.Text="clear"  ' should display "clear" immediately when pressed 
End Sub                 ' and it does


Sub loop1
  Dim size As Int = testarray1.length -1
  Log (size)
  Dim value As Int
  For j= 0 To size
        value = testarray1(j)
        testarray2(j) =value
  Next
End Sub

Sub Loop1_Done
   Label1.text = "End loops"   
End Sub
 

narek adonts

Well-Known Member
Licensed User
Thanks a lot narek ! , it works ok in the release mode.

Global declarations of the two very large arrays to show that it works :

B4X:
Private testarray1 (8000000) As Byte
Private testarray2 (8000000) As Byte
B4X:
Sub Button1_Click
   Label1.Text=""       ' clear the label
   Dim myBGTask As BackgroundTask
   myBGTask.Initialize("loop1",Me)
End Sub

Sub Button2_Click  
   Label1.Text="clear"  ' should display "clear" immediately when pressed
End Sub                 ' and it does


Sub loop1
  Dim size As Int = testarray1.length -1
  Log (size)
  Dim value As Int
  For j= 0 To size
        value = testarray1(j)
        testarray2(j) =value
  Next
End Sub

Sub Loop1_Done
   Label1.text = "End loops"  
End Sub

Great! )
 

marcick

Well-Known Member
Licensed User
Hi narek,
I'm trying to add a parameter (a DbResult object) to the task but I have some difficult in the sintax, could you help me ?
I have modified the initialize like this but that's not all needed

B4X:
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(Subname As String,Module As Object, Result As Object)
    mTaskname=Subname
    mModule=Module
    No(Me).RunMethod("RunThread::",Array(Module,Subname,Result))
End Sub
 

narek adonts

Well-Known Member
Licensed User
Hi narek,
I'm trying to add a parameter (a DbResult object) to the task but I have some difficult in the sintax, could you help me ?
I have modified the initialize like this but that's not all needed

B4X:
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(Subname As String,Module As Object, Result As Object)
    mTaskname=Subname
    mModule=Module
    No(Me).RunMethod("RunThread::",Array(Module,Subname,Result))
End Sub

Could you explain what do you want achieve ?

You can add a Global variable and use it in your background sub.
 

marcick

Well-Known Member
Licensed User
Yes.
I have a DbResult object that contains the result of a RDC query.
Actually I have a For-Next loop that scan all the records and store in a local Database.
This is a very heavy task that freeze the UI for some seconds, so I was trying to use this Background task to see if there are benefits.
So, I need to pass to the sub (Loop1 in your sample) the DbResult OBject. Ok, I can declare it as a global variable, but a parameter to the sub is more elegant.
 

narek adonts

Well-Known Member
Licensed User
DBResult is not a
Yes.
I have a DbResult object that contains the result of a RDC query.
Actually I have a For-Next loop that scan all the records and store in a local Database.
This is a very heavy task that freeze the UI for some seconds, so I was trying to use this Background task to see if there are benefits.
So, I need to pass to the sub (Loop1 in your sample) the DbResult OBject. Ok, I can declare it as a global variable, but a parameter to the sub is more elegant.
Try the new class with new Method - Initialize
I didn't test it so let me know if it works.
 

Attachments

Last edited:

marcick

Well-Known Member
Licensed User
The initialize2 is ok, but the sub declaration doesn't allow to add the parameter

B4X:
    Dim myBGTask As BackgroundTask
       myBGTask.Initialize2("ScanResult",Me, SyncResult)
End Sub

Sub ScanResult (Syncresult As DBResult)        <<< SINTAX ERROR
Am I doing wrong ?
 

marcick

Well-Known Member
Licensed User
Hi. No syntax error now, but it seems the sub is not called. Is it possible ?
 

marcick

Well-Known Member
Licensed User
I confirm that Initialize2 doesn't call the sub. Don't know Initialize3.
Ok, I can use Initialize with a global variable instead to pass the parameter with Initialize2
 

marcick

Well-Known Member
Licensed User
Hi,
if I do nothing while the task is running it works, I just get this red line in the log windows

B4X:
Unexpected event (missing RaisesSynchronousEvents): scanresult:
but if I interact with the program I have other red lines

B4X:
Unexpected event (missing RaisesSynchronousEvents): timer1s_tick
Unexpected event (missing RaisesSynchronousEvents): gmap_camerachange:
and happens that all the app is totally frozen, need to be killed.

This is in debug mode on IOS simulator
In release mode (IOS simulator) everything seems to works fine
 

narek adonts

Well-Known Member
Licensed User
Hi,
if I do nothing while the task is running it works, I just get this red line in the log windows

B4X:
Unexpected event (missing RaisesSynchronousEvents): scanresult:
but if I interact with the program I have other red lines

B4X:
Unexpected event (missing RaisesSynchronousEvents): timer1s_tick
Unexpected event (missing RaisesSynchronousEvents): gmap_camerachange:
and happens that all the app is totally frozen, need to be killed.

This is in debug mode on IOS simulator
In release mode (IOS simulator) everything seems to works fine
As I know in Debug mode everything is running on the Main thread. try it in release mode
I think @Erel can confirm this.
 
Top