Android Tutorial Using CallSubDelayed to interact between activities and services

Discussion in 'Tutorials & Examples' started by Erel, Jun 14, 2012.

  1. Erel

    Erel Administrator Staff Member Licensed User

    Until Basic4android v2.00 the way to pass information between activities and services was through process global variables.

    CallSubDelayed makes it much simpler. It allows you to call a sub in a different service or activity. If the target module is not active, then it will be started automatically. When the target module is ready, the sub will be called.

    CallSubDelayed doesn't immediately call the target sub. It sends a message to the message queue. The internal framework manages this message and passes it to the target module when it is ready.

    CallSubDelayed can also be used to call subs in the current module. It is useful in cases where you want to run some code "right after" the execution of some UI event.

    Rules
    - If the target module is already running then the sub will be called.
    - If the target module is a service and it is not already running then it will first be started (Service_Create and Service_Start will first be executed).
    The sub will be called after Service_Start.
    - If the target module is an activity:
    - If the application is visible (one of its activities is visible) then the target module will be started if needed and the sub will be called.
    - If the application is in the background (can happen when a service calls an activity) then the message will be stored in a special message queue. In this case the sub will be called when the target activity becomes visible. The sub will be called before Activity_Resume.​

    Just to make it clear, you do not need to call StartActivity or StartService when you use CallSubDelayed.
    CallSubDelayed is the recommended method for interaction between activities and services.

    Note that you cannot use CallSubDelayed (or CallSub) with code modules.
    CallSubDelayed can be used with class instances. However the containing module will not be started if it is not already running.

    An improved version of the two activities example:

    Code:
    'Main Activity
    Sub Process_Globals

    End Sub

    Sub Globals
       
    Dim Label1 As Label
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("1")
    End Sub

    Sub Button1_Click
       
    'This call will bring Activity2 to front and will then execute ShowList
       CallSubDelayed2(Activity2, "ShowList""This is the title")
    End Sub
    Sub GetResult(Result As String)
       Label1.Text = 
    "You have chosen: " & Result
    End Sub

    '*****************************
    'Activity2

    Sub Process_Globals
       
    End Sub

    Sub Globals
       
    Dim ListView1 As ListView
    End Sub

    Sub Activity_Create(FirstTime As Boolean)
       
    Activity.LoadLayout("2")
       
    For i = 1 To 100
          ListView1.AddSingleLine(
    "Item #" & i)
       
    Next
    End Sub

    Sub ShowList(Title As String)
       
    Activity.Title = Title
    End Sub

    Sub ListView1_ItemClick (Position As Int, Value As Object)
       
    'this call will bring Main to front and call GetResult
       CallSubDelayed2(Main, "GetResult", Value)
    End Sub
     

    Attached Files:

    Jehoschua, MarkusR, MarcoRome and 8 others like this.
  2. Eugenio Serrano

    Eugenio Serrano Member Licensed User

    Very Useful !

    Thanks a lot !!
     
  3. Roger Garstang

    Roger Garstang Well-Known Member Licensed User

    I don't know how this works/is handled internally, but would it be possible to have 1-3 new subs of this that can specify a delay? 1-3 subs is just to match the current available and have a delay parameter. That way it waits the amount of time before trying to call it. I guess this would be similar to how a Service can be called on a timer, but really a sub.

    I make use of this in the class I'm working on for views and it actually helps a call in one area- Normally when I call the Event sub for my Next button from the keyboard's Done Action button the keyboard doesn't go down before switching to my next activity. When returning from the 2nd activity it is like the animation was paused and the screen finishes shifting down and looks odd. I even had to add a line in Resume to reset my panel height because the IME_HeightChanged doesn't get called either on returning. With this delayed sub call it actually helps out 1 out of 3 times by delaying enough for the keyboard to finish. If it allowed a minimum delay time parameter I think I could delay it long enough for it to finish the sliding. Time in ms would be fine, no need to delay for hours or days or anything.
     
  4. Erel

    Erel Administrator Staff Member Licensed User

    CallSubDelayed implementation is pretty complicated as it needs to deal with starting the target activity or service (if needed) and then waiting for the right time to run.
    It is better to use a timer if you want to have a better timing control.
     
  5. mjas

    mjas Member Licensed User

    Hi Erel,

    congratulations for the great job you do here!!!
    It's wonderfull how quickly the posted questions are answered by someone.

    I'm a newbie with B4A, starting a new project and using your example to create several activities, and switching them bwith "CallSubDelayed".
    Everything goes fine, but the big issue is:
    Because I'l never close anyone of the activities, only switch from one to another, when I am in the Main activity and press the Back button, the Aplication does'n finish, only finishes the Main activity and goes to the next activity in the stack (the last one I opened) and pressing the Back button again do the same (close this one and goes for the next one) and only after pressing the Back button the same number of times like the activities i have finally it goes out for the Home screen.
    Even if I trap the Back button event in Main activity and use "ExitApplication()" it does the same like before but throws an error in Log window:
    "Got RemoteException sending setActive(false) notification to pid 557 uid 10036" because this pid is the Main activity just closed.
    Any idea how this can be fixed?

    BTW: I tried to do this in Manisfest.xml:
    SetActivityAttribute(name of activity , android:noHistory, "true")
    but this doesn't fix this behaviour, only resets each view to the initial state each time it is activated.

    Thank you for any help.:sign0098:
     
  6. Erel

    Erel Administrator Staff Member Licensed User

    Please start a new thread for this question.
     
  7. Rick Harris

    Rick Harris Well-Known Member Licensed User

    Can this two-activities configuration be used to avoid out of memory errors caused by the application being too large? My app is now 25 MB. I wanted to add the Vitamio library, but the additional 8 MB causes my app to crash.
    Would my OOM problem maybe be solved if I added the Vitamio library (by Warwound) in a separate activity?
     
  8. Erel

    Erel Administrator Staff Member Licensed User

    No. It will not help. Are you loading large bitmaps?
     
  9. Antti Mauranen

    Antti Mauranen Member Licensed User

    Is it possible to make the message wait queue longer? When the main activity is paused and my service calls CallSubDelayed, it seems that I can add only 21 messages to wait queue and then I get warning that the queue is full. See below.

    ** Service (bleservice) Start **
    sending message to waiting queue (CallSubDelayed - Add_Error_Line)
    Ignoring event (too many queued events: CallSubDelayed - Add_Error_Line)
    ** Service (bleservice) Start **
    sending message to waiting queue (CallSubDelayed - Add_Error_Line)
    Ignoring event (too many queued events: CallSubDelayed - Add_Error_Line)
    running waiting messages (21)
    ** Activity (main) Resume **
    ** Service (bleservice) Start **
     
  10. Erel

    Erel Administrator Staff Member Licensed User

    The problem is that when the activity is resumed all the events will be executed. So there must be some limit.

    In most cases, if you are reaching this limit then it is a good sign that you need to use a service instead of an activity.
     
  11. Antti Mauranen

    Antti Mauranen Member Licensed User

    I tried to collect messages into a list in the service and then send them in one burst when the activity gets out of pause state. That method loses messages also.

    Then I tried to send the messages little slower (had 10 ms delay between messages every message), still loses messages.

    Maybe I start to read the messages in the activity create, after the activity gets out of pause state (anyway, I have access to BleService.waitList). I will try that.

    Lots of learn about this beast :).
     
  12. Erel

    Erel Administrator Staff Member Licensed User

    Why can't you handle these messages in the service?
     
  13. Antti Mauranen

    Antti Mauranen Member Licensed User

    Hello Erel,

    yes, I will read the message in the service and do some actions in the service. But I also want to write an indication (one line per message) about every message into CustomListView in my main action. So my problem is how do I insert a new row into CLV. Now a) when main activity is active, I use CallSubDelayed and b) when main activity is in the background, I collect the (future) traffic between service and CLV into a list and when the main activity comes active, I read that list from Activity_Resume.

    This seems to function. I do not know if that is a good way.
     
  14. Erel

    Erel Administrator Staff Member Licensed User

    This is a good solution. You should however understand that the process can be killed while it is in the background. If it is a problem than you need to persist this list (use KeyValueStore).
     
  15. Antti Mauranen

    Antti Mauranen Member Licensed User

    Good point that possible process death. I have to check KeyValueStore. Thanks.
     
    Last edited: Dec 20, 2013
  16. Ratna Fang

    Ratna Fang Member Licensed User

    hi erel,

    i simply use callsubdelayed in this code, in the main activity to call another activity (Menu2 activity).
    Code:
    Sub ImageView1_Click
        CallSubDelayed(Menu2,
    "Activity_Create")
    End Sub

    no error found when compiling, but in the device, i got an error message "activity_create does not match expected signature".

    here is the code of activity_create in Menu2
    Code:
    Sub Activity_Create(FirstTime As Boolean)
        
    'Do not forget to load the layout file created with the visual designer. For example:
        Activity.LoadLayout("Menu1")

        List1.Initialize(
    "ListView1")

        List1.AddTwoLines (
    "1","one")
        List1.AddTwoLines (
    "2","two")
        List1.AddTwoLines (
    "3""three")
    End Sub
    is there anything wrong? or i should use startactivity(Menu2) for this case?
     

    Attached Files:

    Last edited: Dec 21, 2013
  17. Erel

    Erel Administrator Staff Member Licensed User

    You are missing the sub parameter in your call. You should use CallSubDelayed2 instead. However I don't think that you are using this method correctly.
    If you just want to start an activity then you should call StartActivity. CallSubDelayed allows you to directly call a sub (and pass parameters) in another activity or service.
     
  18. Ratna Fang

    Ratna Fang Member Licensed User

    thanks erel :)
    i got the basic idea now
     
  19. andrewj

    andrewj Active Member Licensed User

    Hi,
    Is there any way to pause after/at the end of processing the delayed sub? I'm loading images into a display which works well, in that now my screen shows the activity with the images empty, and then fills them through a series of delayed calls. However the screen still only shows the images when all delayed subs have completed, whereas I'd like it to refresh after each one.
    Thanks
    Andrew
     
  20. Erel

    Erel Administrator Staff Member Licensed User

    Where do these images come from?
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice