Android Question Indirect CallSub in Activity_Create works but is it safe

SteveTerrell

Active Member
Licensed User
Longtime User
Hi,
It is known that CallSub does not work in Activity_Create (because the process is paused).
It does however seem to work if called indirectly in a class.

I have a StateManagerClass which is used by other classes and code.

B4X:
'These are in Main  
Sub Process_Globals
    Public screenManager As StateManagerClass
    Public meterManager As MeterManagerClass
...

Sub Activity_Create 'Main
If FirstTime Then
        screenManager.Initialize("ScreenManager",Me,"ScreenManagerStateMachineCode")
        screenManager.EventRun(GlobalEventNames.EVT_INITIAL_EVENT_RUN,Null)    ' doesnt run
        meterManager.Initialize()
End If


In the MeterManagerClass
B4X:
Sub Class_Globals
    Private manager As StateManagerClass
...

Public Sub Initialize
    manager.Initialize("MeterManager",Me,"StateMachineCode")
    manager.EventRun(GlobalEventNames.EVT_INITIAL_EVENT_RUN, Null)   'does run
End Sub

In StateManagerClass
B4X:
Public Sub EventRun(event As Int, data As Object)
    CallSub3(Module, StateCode, event, data)
End Sub


screenManager users the StateManagerClass directly - the CallSub3 in EventRun does not execute.
meterManager uses the MeterManagerClass which uses StateManagerClass - the CallSub3 does execute


This seems a little inconsistent, is it Safe to do this?

P.S. I know if EventRun uses CallSubDelayed always works, but it does complicate the create timing in my application.
 

SteveTerrell

Active Member
Licensed User
Longtime User
I need a small example in order to better understand it. Can't you use CallSubDelayed(Me, "RunAfterActivityCreate") in Activity_Create to call a sub that will run after Activity_Create?

Hi, example attached.

Log file looks like this
B4X:
** Activity (main) Pause, UserClosed = true **
** Activity (main) Resume **
** Service (starter) Destroy **
** Activity (main) Pause, UserClosed = false **
** Service (starter) Create **
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
SomeClassCode:Executing CallSub3SomeClassCode
TwoLevelClassCode:Executing CallSub3TwoLevelClassCode
TwoLevelClassCode:Called by CallSub3:1:2
End of activity_create
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
** Service (starter) Destroy **
** Activity (main) Resume **

Attempt at simple explanation...

In Main:
B4X:
Sub Process_Globals
    Public pSomeClass As SomeClass
    Public pTwoLevelClass As TwoLevelClass
End Sub

Sub Globals
End Sub

Sub Activity_Create(FirstTime As Boolean)
    pSomeClass.Initialize(Me, "SomeClassCode")
    pTwoLevelClass.Initialize()
    Log("End of activity_create")
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub SomeClassCode(event As Int, str As String)
    Log("SomeClassCode:"&event&":"&str)
End Sub

SomeClass
B4X:
Sub Class_Globals
    Public codeLocation As Object
    Public codeName As String
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(subLocation As Object, subName As String)
    codeLocation = subLocation
    codeName = subName
    Log(codeName&":Executing CallSub3"&codeName)
    CallSub3(codeLocation, codeName, 1, "2")
End Sub

TwoLevelClass
B4X:
Sub Class_Globals
    Public pSomeClass As SomeClass
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize()
    pSomeClass.Initialize(Me, "TwoLevelClassCode")
End Sub

Sub TwoLevelClassCode(event As Int, str As String)
    Log("TwoLevelClassCode:Called by CallSub3:"&event&":"&str)

TwoLevelClass uses its own instance of SomeClass and initialises it with pointers to its own code.
SomeClass Initialise calls the given target code using CallSub3.
The target for the CallSub3(s) just identifies itself in the log.

From the log (and tracing) it can be seen that the CallSub3 in the "Main" SomeClass instance is not executed (no log entry) but,
the CallSub3 in the instance of SomeClass in TwoLevelClass is executed.

Execution seems to depend upon where the target code for the CallSub3 is located rather than just on the activity progress.
If it is in Main it is not called, if it is in a class it is called.

Your solution of using a general CallSubDelayed for initialisation would of course work as would replacing the CallSub3 with CallSubDelayed3.

I was attempting to increase the readability and consistency of my code when I encountered this anomaly.

Steve
 

Attachments

  • example.zip
    7.5 KB · Views: 136
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Execution seems to depend upon where the target code for the CallSub3 is located rather than just on the activity progress.
If it is in Main it is not called, if it is in a class it is called.
That's true. If the target is a class then CallSub will always work. If it is an Activity or Service then CallSub will only work if the target is considered running (after Activity_Create or Service_Create).
 
Upvote 0

SteveTerrell

Active Member
Licensed User
Longtime User
That's true. If the target is a class then CallSub will always work. If it is an Activity or Service then CallSub will only work if the target is considered running (after Activity_Create or Service_Create).

Thanks, that explains it!

I like your recommendation regarding the callsubdelayed in activity_create.

Steve
 
Upvote 0

SteveTerrell

Active Member
Licensed User
Longtime User
Thanks, that explains it!

I like your recommendation regarding the callsubdelayed in activity_create.

Steve

Just a follow up to that approach, the delayed activity create does not run until after the Activity_Resume so any code in resume which relies on initialisation in create will fail.
Looks like a Delayed_Activity_Resume is required to get the relative timing correct.

Steve
 
Upvote 0
Top