Other Quiz #12 - Find the bug - Process & Activities life cycle

Erel

B4X founder
Staff member
Licensed User
Longtime User
This one should be quite simple. Find and explain the bug in each of the following code snippets:

1.
B4X:
'main
Sub Process_Globals

End Sub

Sub Globals
   Dim sql1 As SQL
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     sql1.Initialize(File.DirRootExternal, "1.db", False)
   End If
End Sub

2.
B4X:
'main
Sub Process_Globals
   Public sql1 As SQL
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     sql1.Initialize(File.DirRootExternal, "1.db", False)
   End If
   StartServiceAt(Service1, DateTime.Now + 1 * DateTime.TicksPerHour, True)
End Sub

'Service1
Sub Service_Create
Log(Main.sql1.ExecQuerySingleResult("SELECT Count(*) From Table1"))
End Sub

3.
B4X:
Sub Process_Globals
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
     Activity.LoadLayout("Layout1")
   End If
End Sub

4.
B4X:
Sub Activity_Pause (UserClosed As Boolean)
   If Msgbox("Do you want to save changes?", "") = DialogResponse.POSITIVE Then
     SaveChanges
   End If
End Sub
 

corwin42

Expert
Licensed User
Longtime User
1.
FirstTime is true if the activity is created the first time for this process. Variables in Globals get initialized every time the activity is created. So if the device is rotated the activity get recreated and so the sql1 variable will be dimmed again. But it will then not be initialized again because the process is still running and FirstTime will be false in this case.

2.
The service will be started one hour in the future. The problem is that the system may decide to kick the process out of memory in this time but the service will still start at the given time. So when the service starts there is a chance that the sql1 variable isn't initialized anymore.

3.
This is quite similar to the 1st problem. The layout only gets loaded if the activity wasn't created for this process. If you rotate the device the process keeps running, FirstTime is false and the layout does not load. The system may even decide to kill an activity if it is not visible and the problem can occur if you just start another app and you bring this activity to front after some time.

4.
The Msgbox waits until the user closes it. This is a bad thing in Activity_Pause, Activity_Resume etc. because you will get an ANR (Application Not Responding) error.

Haven't tried the code snippets. Just my thoughts about it.
The answers should be put into some form of FAQ. :)

Edit:

See the additional comments from Erel in post #4

Additional comment for 2.
In addition to Erels comment in #4 the same problem can happen with two Activities. The Main Activity is not always called when the process and another activity gets created. Be sure to make all your necessary (global) initializations in Activity_Create() of EVERY Activity and Service_Create() in EVERY service module.
 
Last edited:
Upvote 0

Yalçın Kondur

Member
Licensed User
Longtime User
as a small addition to corwin42, the first code snippet will fail if user removed external storage or device has no external storage installed.
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Very good @corwin42 !!!

Some comments:
1. The explanation is 100% correct. The solution is to move the declaration of sql1 to Sub Process_Globals. Removing the FirstTime condition is not a good solution as the object will be unnecessarily initialized multiple times.

2. The solution for this issue is to either check whether the object is initialized and then initialize it, or create a module that is responsible for the initialization and call it from Activity_Create and Service_Create.

4. The Msgbox call will be ignored returning DialogResponse.Cancel as modal dialogs are not allowed in Activity_Pause. There will also be a compiler warning.

as a small addition to corwin42, the first code snippet will fail if user removed external storage or device has no external storage installed.
This is correct as well (though it was not intended). DBUtils.CopyDBFromAssetsFile is a good example of handling this issue.
 
Upvote 0
Top