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

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

  • BackgroundTask.bas
    2.5 KB · Views: 135
Last edited:

JackKirk

Well-Known Member
Licensed User
Longtime User
Narek,

What a potentially fascinating bit of code.

I am trying to use it to extract "brightness" from a bitmap.

I get an error dump:
B4X:
Unexpected event (missing RaisesSynchronousEvents): event_bc_scanner_stillimage_background:
Error occurred on line: 561 (ZXBarcodeScanner)
-[UIImage object]: unrecognized selector sent to instance 0x155902c0
Stack Trace: (
  CoreFoundation       <redacted> + 150
  libobjc.A.dylib      objc_exception_throw + 38
  CoreFoundation       <redacted> + 0
  CoreFoundation       <redacted> + 700
  CoreFoundation       _CF_forwarding_prep_0 + 24
  my24-7laundry        -[b4i_zxbarcodescanner _event_bc_scanner_stillimage_background::] + 832
  CoreFoundation       <redacted> + 68
  CoreFoundation       <redacted> + 292
  my24-7laundry        +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1786
  my24-7laundry        -[B4IShell runMethod:] + 574
my24-7laundry        -[B4IShell raiseEventImpl:method:args::] + 1998
my24-7laundry        __40-[B4IShell raiseEventImpl:method:args::]_block_invoke + 38
libdispatch.dylib    <redacted> + 10
libdispatch.dylib    <redacted> + 22
libdispatch.dylib    <redacted> + 1524
CoreFoundation       <redacted> + 8
CoreFoundation       <redacted> + 1574
CoreFoundation       CFRunLoopRunSpecific + 520
CoreFoundation       CFRunLoopRunInMode + 108
GraphicsServices     GSEventRunModal + 160
UIKit                UIApplicationMain + 144
my24-7laundry        main + 108
libdyld.dylib        <redacted> + 2
)

When I put the following code in the background task:
B4X:
559 'Extract bitmap to a byte array
560 Private no As NativeObject = Me
561 Private bmp_bytes() As Byte = no.NSDataToArray(no.RunMethod("BitmapToArray:", Array(Image)))    '<<<<<< fails here

If I do the bitmap to byte array conversion outside the background task and pass the byte array to the background task all seems to work fine.

I take it that the bitmap is considered UI? - it isn't really.

The main reason for looking at backgrounding the "brightness" extraction is because the bitmap to byte array conversion is a cycle gobbler.

Any comments or suggestions welcome.

Thanks in anticipation...
 

narek adonts

Well-Known Member
Licensed User
Longtime User
Narek,

What a potentially fascinating bit of code.

I am trying to use it to extract "brightness" from a bitmap.

I get an error dump:
B4X:
Unexpected event (missing RaisesSynchronousEvents): event_bc_scanner_stillimage_background:
Error occurred on line: 561 (ZXBarcodeScanner)
-[UIImage object]: unrecognized selector sent to instance 0x155902c0
Stack Trace: (
  CoreFoundation       <redacted> + 150
  libobjc.A.dylib      objc_exception_throw + 38
  CoreFoundation       <redacted> + 0
  CoreFoundation       <redacted> + 700
  CoreFoundation       _CF_forwarding_prep_0 + 24
  my24-7laundry        -[b4i_zxbarcodescanner _event_bc_scanner_stillimage_background::] + 832
  CoreFoundation       <redacted> + 68
  CoreFoundation       <redacted> + 292
  my24-7laundry        +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1786
  my24-7laundry        -[B4IShell runMethod:] + 574
my24-7laundry        -[B4IShell raiseEventImpl:method:args::] + 1998
my24-7laundry        __40-[B4IShell raiseEventImpl:method:args::]_block_invoke + 38
libdispatch.dylib    <redacted> + 10
libdispatch.dylib    <redacted> + 22
libdispatch.dylib    <redacted> + 1524
CoreFoundation       <redacted> + 8
CoreFoundation       <redacted> + 1574
CoreFoundation       CFRunLoopRunSpecific + 520
CoreFoundation       CFRunLoopRunInMode + 108
GraphicsServices     GSEventRunModal + 160
UIKit                UIApplicationMain + 144
my24-7laundry        main + 108
libdyld.dylib        <redacted> + 2
)

When I put the following code in the background task:
B4X:
559 'Extract bitmap to a byte array
560 Private no As NativeObject = Me
561 Private bmp_bytes() As Byte = no.NSDataToArray(no.RunMethod("BitmapToArray:", Array(Image)))    '<<<<<< fails here

If I do the bitmap to byte array conversion outside the background task and pass the byte array to the background task all seems to work fine.

I take it that the bitmap is considered UI? - it isn't really.

The main reason for looking at backgrounding the "brightness" extraction is because the bitmap to byte array conversion is a cycle gobbler.

Any comments or suggestions welcome.

Thanks in anticipation...

it is strange.

Try to create a Sub like this

B4X:
Sub GetByteFromBitmap(img As Bitmap, Quality As Int) As Byte()
      Dim out As OutputStream
      Dim data() As Byte
      out.InitializeToBytesArray(1)
      img.WriteToStream(out,Quality,"JPEG")
      data = out.ToBytesArray
      out.Close
      Return data

' credits to jaraiza

End Sub

and use this sub in your backgroundTask

Narek
 

narek adonts

Well-Known Member
Licensed User
Longtime User
I think I found the issue. There is problem passing parameters with the Class.


Try this

B4X:
Sub GetByteFromBitmap(img As Object, Quality As Int) As Byte()
      Dim out As OutputStream
      Dim data() As Byte
      out.InitializeToBytesArray(1)
      Dim tmpImg as Bitmap=img
      tmpImg.WriteToStream(out,Quality,"JPEG")
      data = out.ToBytesArray
      out.Close
      Return data

' credits to jaraiza

End Sub


Or post your Background Sub and I will correct it.

The issue is that you should declare the parameters as Object (for bitmap).
 
Last edited:

narek adonts

Well-Known Member
Licensed User
Longtime User
Narek,

What a potentially fascinating bit of code.

I am trying to use it to extract "brightness" from a bitmap.

I get an error dump:
B4X:
Unexpected event (missing RaisesSynchronousEvents): event_bc_scanner_stillimage_background:
Error occurred on line: 561 (ZXBarcodeScanner)
-[UIImage object]: unrecognized selector sent to instance 0x155902c0
Stack Trace: (
  CoreFoundation       <redacted> + 150
  libobjc.A.dylib      objc_exception_throw + 38
  CoreFoundation       <redacted> + 0
  CoreFoundation       <redacted> + 700
  CoreFoundation       _CF_forwarding_prep_0 + 24
  my24-7laundry        -[b4i_zxbarcodescanner _event_bc_scanner_stillimage_background::] + 832
  CoreFoundation       <redacted> + 68
  CoreFoundation       <redacted> + 292
  my24-7laundry        +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1786
  my24-7laundry        -[B4IShell runMethod:] + 574
my24-7laundry        -[B4IShell raiseEventImpl:method:args::] + 1998
my24-7laundry        __40-[B4IShell raiseEventImpl:method:args::]_block_invoke + 38
libdispatch.dylib    <redacted> + 10
libdispatch.dylib    <redacted> + 22
libdispatch.dylib    <redacted> + 1524
CoreFoundation       <redacted> + 8
CoreFoundation       <redacted> + 1574
CoreFoundation       CFRunLoopRunSpecific + 520
CoreFoundation       CFRunLoopRunInMode + 108
GraphicsServices     GSEventRunModal + 160
UIKit                UIApplicationMain + 144
my24-7laundry        main + 108
libdyld.dylib        <redacted> + 2
)

When I put the following code in the background task:
B4X:
559 'Extract bitmap to a byte array
560 Private no As NativeObject = Me
561 Private bmp_bytes() As Byte = no.NSDataToArray(no.RunMethod("BitmapToArray:", Array(Image)))    '<<<<<< fails here

If I do the bitmap to byte array conversion outside the background task and pass the byte array to the background task all seems to work fine.

I take it that the bitmap is considered UI? - it isn't really.

The main reason for looking at backgrounding the "brightness" extraction is because the bitmap to byte array conversion is a cycle gobbler.

Any comments or suggestions welcome.

Thanks in anticipation...
For your issue if you will change the parameter part (Image as Bitmap) to (Image as Object) and after

Dim tmpImg as Bitmap=Image

Private no As NativeObject = Me
Private bmp_bytes() As Byte = no.NSDataToArray(no.RunMethod("BitmapToArray:", Array(tmpImg))) it should work
 

JackKirk

Well-Known Member
Licensed User
Longtime User
For your issue if you will change the parameter part (Image as Bitmap) to (Image as Object) and after

Dim tmpImg as Bitmap=Image

Private no As NativeObject = Me
Private bmp_bytes() As Byte = no.NSDataToArray(no.RunMethod("BitmapToArray:", Array(tmpImg))) it should work
Narek,

That did the trick - now working beautifully.

Many Thanks...
 

JackKirk

Well-Known Member
Licensed User
Longtime User
What a potentially fascinating bit of code.
Narek,

I have changed my assessment to "what an unequivocally brilliant bit of code".:)
 

JackKirk

Well-Known Member
Licensed User
Longtime User
Narek,

Looking at your latest version of your class at post #1, I notice in the Objective C:

-(void)RunThread4: ...

but RunThread4 doesn't seem to be used anywhere - am I missing something?

Regards...
 

JackKirk

Well-Known Member
Licensed User
Longtime User
Narek,

Maybe a little tip for others using your class...

When running your class in my project in DEBUG mode I get a series of non-fatal log messages of the form:

Unexpected event (missing RaisesSynchronousEvents): ...

I have found I can suppress these messages by wrapping the initiation of the background task like so:
B4X:
#IF RELEASE
 
    'Process task in background
    myBGTask.Initialize("MyTask",Me,Array(yourParam))

#ELSE
 
    'Process task in foreground
    MyTask(yourParam)

#END IF


and placing the following as the last statements in MyTask:
B4X:
#IF RELEASE

    'Do nothing - MyTask_Done will be automatically fired by myBGTask

#ELSE

    'Complete processing MyTask in foreground
    MyTask_Done

#END IF
Regards...
 
Last edited:

JackKirk

Well-Known Member
Licensed User
Longtime User
myBGTask.Initialize("MyTask",Me,Array(Null))
Narek,

The above does not work, this does:

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

Suggest you change the 2 references in your post #1 to reflect this.

Also, if you are editing your post #1 you might like to change:

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

to

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

I know, I know, I am a picky pedantic bastard, but your class deserves full polish.

I continue to be awed - it would appear that not only can I process an image in the background but I can also capture it there.

Regards...
 
Top