Android Question Activities Cycle, Changing Orientations, and Object Initializations

Guardian17

Active Member
Licensed User
Longtime User
One of the most daunting and frustrating aspects of Android programming is handling the Activities Cycle after a screen orientation change. The game app I have been working on for many months works just fine in either orientation if I do not change orientations -- I can play game after game for hours without any problems if I do not change orientations. And I have been able to handle many aspects of restoring the game after a screen orientation change, but I still have problems with some objects that are not initialized or which already have a parent when I change orientations. Adding tons of IF statements to determine if objects are already initialized before possibly re-initializing them (which I have been recently doing) seems like something that should not be necessary.

My question is: what is the best way to handle restoring objects after an orientation change? Is it best to re-load ALL layouts (my current App has 20 layouts, which would probably take considerable time between orientation changes), and generate associated sub-views on Resume, but keep the associated backpanels into which those layouts and views are loaded invisible until later needed? Or is there some other/better way to restore objects?

My apologies for not being able to provide an exported ZIP file as the current App is way too large to do so to show the problems I'm encountering, and it may not be possible to cut out sections of my code to be able to make an exportable ZIP file because this may mask the problems I am encountering.
 
Last edited:

Guardian17

Active Member
Licensed User
Longtime User
Sorry it took so long to reply as I was busy making up the infographic (below):

Activity Cycle - Orientation Changes - and Layouts.png


The infographic shows how my current game operates -- everything is in one Activity. The green boxes are individual Layouts that get loaded -- WHEN NEEDED. In all cases after exiting the associated overlay panel, I remove all sub-views and then remove that panel from the Activity.

I mis-spoke earlier - I do have 20 layouts, but almost half of them are "duplicates" for the two screen orientations. Aside from the 3 layouts that are on the Main PlayScreen, (well, 4 if you count the Give-Up Panel), only one other layout is ever loaded on an overlay panel, so there are a maximum of 5 layouts loaded at any one time.

I did some homework on this Forum and found an excellent post related to my situation here:
https://www.b4x.com/android/forum/threads/when-to-use-activities-and-why.46284/#content

I can understand the benefits of calling other Activities -- my ONE Activity has a LOT of overhead for variable declarations for ALL of the other panel layouts. I assume that each separate Activity would handle its own set of variables that would not need to be cited in the original Activity.

In regards to calling other Activities, I have a few questions:
1) When I issue the command: StartActivity("myactivityname"), does all "activity" in the original code that Started the other Activity stop completely and the new Activity takes over completely?
2) What happens if Timers are running in the original code that invoked the new Activity? Do those Timers need to be disabled before starting the new Activity?
3) When the invoked Activity is done doing what it has to do, does it just execute an Activity.Finish command and any views and overlay panels vanish from the screen, allowing the original Activity to continue from where it left off (at the very next instruction after the "StartActivity" call)?
4) Where does the other Activity code reside in the overall Project? Does it become a separate .bas file or module and get placed in the Root directory of the Project?

Thanks in advance for any help/answers to these questions.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I recommend you to start with this very important tutorial: Android Process and activities life cycle

1) Activity_Pause of the current activity will be called and then the next activity will be started. Events will only be raised in the visible activity. Use a service if you need a timer to continue running after the activity is paused.

2) It is recommended to disable timers in Activity_Pause.
3) The code doesn't stop in any case. StartActivity sends a message to the message queue that later starts the next activity.
4) Each activity code is in a separate module.
 
Upvote 0

Guardian17

Active Member
Licensed User
Longtime User
Thanks Erel. I have read the "Activities Process and Activities Life Cycle" several times, but probably not to the depth that I should have because certain things didn't pertain to me at the time.

Clarification 1 (please verify): When the original Activity is re-started, ONLY Activity_Resume is executed ... Activity_Create is NOT run in this case -- so any layouts and Process variables that were loaded in the original Activity_Create will still be present upon return to the original Activity (assuming the original Activity was not destroyed by the Android OS for some reason).


3) The code doesn't stop in any case. StartActivity sends a message to the message queue that later starts the next activity.

In the following code snippet example, UpdateSettings is declared in Process_Globals and its value can be changed in myotheractivity:
B4X:
Sub InvokeOtherActivity
   UpdateSettings = False
   StartActivity("myotheractivity")
   If UpdateSettings = True Then
      UpdateProgramSettings
   End If
   '<Other code>
End Sub

Clarification 2 (any or all of the following statements may not be true):
[[EDIT: See Post #10 below for corrected statements]]
1) The IF statement and any "<other code>" in the same Sub will always be executed immediately after StartActivity is executed, even while the second Activity is starting up,
OR
2) The current Activity_Pause begins executing immediately after the StartActivity instruction is executed, and the IF statement NEVER gets executed,
OR
3) Some instructions after the StartActivity instruction may execute until the Android OS gets the message queue message to start the second Activity (but UpdateSettings may not have been changed yet by myotheractivity). Then the first Activity gets halted, the first Activity_Pause gets executed, and the new Activity's Activity_Create is run.
OR
4) Some other sequence of events.

Which is the correct scenario, and if it's (4), what is the correct sequence of events?
 
Last edited:
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
I would need to run some tests to confirm the operation but I believe that StartActivity("myotheractivity") will send a message to the system to start your other Activity. But in the meantime the rest of the Sub will finish executing and the IF UpdateSettings will never get executed because you set it to False before making the call to start your other Activity. Activity_Pause will also get triggered I think before your new Activity loads.

Can't you move the UpdateProgramSettings and whatever followed the IF statement into the Activity_Create of "myotheractivity"?

If I'm wrong on any of the above I'm sure that I'll soon be corrected by one of the other more knowledgeable members or Erel. :D
 
Upvote 0

Guardian17

Active Member
Licensed User
Longtime User
My apologies if I misled anyone on this. I was trying to clarify how StartActivity actually works in the context of the Activity Cycle. I thought the example shown (which is not actual code in my App) would allow a better method to cite which instructions do get executed and precisely WHEN they get executed in relation to the execution of the StartActivity instruction. I am also interested in defining when Activity_Pause starts being executed as a result of StartActivity executing, and precisely WHEN the code in the second Activity begins executing.

Before starting this Thread, I had thought that StartActivity acted more the way that Subs are executed, such that the StartActivity instruction would immediately run myotheractivity (like a Sub) and then return to the instruction immediately following the StartActivity instruction and continue execution from there. It seems that this is not correct.

From everything I know so far, Activity_Pause will always be executed for the original Activity before the second Activity starts, it's just a question of exactly WHEN that happens and how much code in the original Activity (after the StartActivity instruction) gets executed before its Activity_Pause runs. From what you, RandomCoder, have said, it would appear that any code in the Sub that follows the StartActivity instruction will be executed to the end of that Sub, and then Activity_Pause will run prior to the second Activity starting.

I will try some experiments to prove the exact order of events, which may take a bit of time since I have not used StartActivity in any Apps to this point.
 
Upvote 0

RandomCoder

Well-Known Member
Licensed User
Longtime User
Hi @Guardian17 this is my understanding of the order of things. I'm not at my PC at the moment but to test whether or not I am correct I would just add a Log statement at the start and end of each Sub and test which order things happen in. Remember that there is only one Main thread (unless you choose to use the Threading library)and so only one thing can be happening at any point in time.
 
Upvote 0

Guardian17

Active Member
Licensed User
Longtime User
I found a great simple example (provided by Erel) of using two Activities here:
https://www.b4x.com/android/forum/threads/two-activities-example.6611/

In order to prove what I am trying to prove, I have modified Erel's Button1_Click code slightly to add a few Log messages and a delay loop immediately after the StartActivity instruction (please see the attached project: TwoActivities2.zip)

B4X:
Sub Button1_Click
    StartActivity(Activity2)
    Log("This statement occurs right after Activity2 Started")
    For k=0 To 100000
        If (k Mod 10000) = 0 Then
            Log("k = " & k)
        End If
    Next
    Log("This statement occurs after the Main Activity delay loop")
End Sub


This is the result that occurs in the Log window of my example when the program is run and Button1 is clicked (and includes a subsequent Click in Activity2):
===================================
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
This statement occurs right after Activity2 Started
k = 0
k = 10000
k = 20000
k = 30000
k = 40000
k = 50000
k = 60000
k = 70000
k = 80000
k = 90000
k = 100000
This statement occurs after the Main Activity delay loop
** Activity (main) Pause, UserClosed = false **
** Activity (activity2) Create, isFirst = true **
** Activity (activity2) Resume **
** Activity (activity2) Pause, UserClosed = false **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
===================================

So, as you can see, Activity_Pause in the Main Activity does not occur until the END of the SUB in which StartActivity is used (which, in my example, occurs several seconds later).

AND, I have also verified my "Clarification 1", which is seen at the end of the Log window, where only Activity_Resume is executed in Main, while Activity_Create in Main is NOT executed.

I also learned that, to exit the second Activity to return to the Main Activity, you issue a StartActivity(Main) instruction in the second Activity (as opposed to using an Activity.Finish instruction).

I'm glad I was able to clarify this, with thanks to Erel and RandomCoder, and I hope it helps others that want to use other Activities in their Apps.
 

Attachments

  • TwoActivities2.zip
    13 KB · Views: 196
Last edited:
Upvote 0

Guardian17

Active Member
Licensed User
Longtime User
To clarify what was speculated in Post #5 above
1) The IF statement and any "<other code>" in the same Sub will always be executed immediately after StartActivity is executed, even while the second Activity is starting up
It would seem that the remaining code in the Sub in which StartActivity was used will be executed, but this is PRIOR to Activity_Resume for the current Activity being executed, and certainly before the other Activity actually starts.

2) The current Activity_Pause begins executing immediately after the StartActivity instruction is executed, and the IF statement NEVER gets executed
NOT CORRECT. Activity_Pause waits until all code in the Sub in which ActivityStart was used is executed. And, since the second Activity has not yet been started, it cannot have yet affected the UpdateSettings variable, so the body of the IF statement will never be executed because UpdateSettings will never be True at that point in the code.

3) Some instructions after the StartActivity instruction may execute until the Android OS gets the message queue message to start the second Activity (but UpdateSettings may not have been changed yet by myotheractivity). Then the first Activity gets halted, the first Activity_Pause gets executed, and the new Activity's Activity_Create is run.
ALL instructions in the current Sub in which StartActivity is used will be executed according to the logic of the code until the end of that Sub is reached, then Activity_Resume is executed, and then the new Activity is started.
 
Last edited:
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Erel would answer: "you should not lock the Main thread with those loops".

You can avoid the execution of code after StartActivity using Return immediately after StartActivity (of course, it would not make sense unless there is a condition: "If Something Then Return")
 
Upvote 0

Guardian17

Active Member
Licensed User
Longtime User
Erel would answer: "you should not lock the Main thread with those loops".
It was only my intention to show in the example that an appreciable amount of time can elapse until the end of the Sub (in which StartActivity was used) has been reached BEFORE Activity_Resume is executed. I certainly don't approve of large, essentially do-nothing, loops in my code to mess up the main thread.
 
Upvote 0

Guardian17

Active Member
Licensed User
Longtime User
I also learned that, to exit the second Activity to return to the Main Activity, you issue a StartActivity(Main) instruction in the second Activity (as opposed to using an Activity.Finish instruction).

I have further learned that, although you can use StartActivity(Main) to exit the second Activity, it is usually better to use Activity.Finish to exit the second Activity. If you use StartActivity(Main), the Second Activity may remain in memory in a Paused State, such that if you have returned to the Main Activity, and you use the BACK button to exit the Main Activity, the Second Activity may re-appear/re-start.
 
Last edited:
Upvote 0
Top