Android Question Execution Loop and State

Frank Cazabon

Member
Licensed User
Longtime User
I've got the core of my application working but am having some issues with the display of data when the device switches orientation (rotates).

From what I've read here this is my understanding of the execution loop:

Program starts, Activity_Create runs (The first time it runs a Boolean variable FirstTime is true).

If the orientation of the device changes, Activity_Pause gets called, then Activity_Create (with FirstTime = false), then Activity_Resume.

If the device display times out and switches off (the display, not the device) the execution is Activity_Pause, then when it wakes up again Activity_Create and Activity_Resume.

Is that right?

I have a single activity application. In this Activity I load my main layout which has a tabhost on it, then I tabHost.AddTab() 4 tabs each with their own layout.

On 3 of these tabs I have a listview (actually one is a plain list view and the other 2 are listviews but using the SearchView example, although that shouldn't make a difference).

Based on the above logic I am trying to display the data in my list views when the orientation changes or the device goes into power save. However, the list on the first tab displays nothing in it when the application first starts, but displays the list when the orientation changes.

The other lists display when the application first starts but not when the orientation changes. Also, the correct tab does not get displayed when the orientation changes.

So I've got my logic wrong somewhere :(

B4X:
Sub Activity_Pause (UserClosed As Boolean)
    If UserClosed Then

    Else
        CurrentPage = tbhMain.CurrentTab
    End If
End Sub

Sub Activity_Resume
    SetRouteList    'listview on first tab
    BuildLoadList    'listview on 2nd tab
    BuildDeliveryList   'listview on 3rd tab
    tbhMain.CurrentTab = CurrentPage
End Sub

These are the procedures that build the lists:

B4X:
Sub SetRouteList
    Dim Routes As List
    Routes = DBUtils.ExecuteMemoryTable(SQLLite, "SELECT rte_name FROM Routes", Null, 0)

    For i = 0 To Routes.Size - 1
        Dim route() As String
        route = Routes.Get(i)
        lvwRoutes.AddSingleLine(route(0))
    Next
   
End Sub

Sub BuildLoadList As List
    Dim AWBs As List
    AWBs = DBUtils.ExecuteMemoryTable(SQLLite, "SELECT awb_number, cus_company, del_scancode FROM RunSheetDetails LEFT JOIN DeliveryHistory ON rnd_pk = del_rndfk AND del_scancode = 1 ORDER BY cus_company", Null, 0)
    Return AWBs
End Sub

Sub BuildDeliveryList As List
    Dim x As List
    x = DBUtils.ExecuteMemoryTable(SQLLite, "SELECT DeliveryHistory.* FROM DeliveryHistory",Null,0)
   
    Dim Deliveries As List

    Deliveries = DBUtils.ExecuteMemoryTable(SQLLite, _
                    "SELECT awb_number, cus_company, DeliveryHistory.del_scancode, " _
                            & "DeliveryHistory.del_delivered " _
                            & ", cus_number " _
                            & "FROM DeliveryHistory " _
                            & "INNER JOIN (SELECT MAX(del_time) AS Latest, del_rndfk FROM DeliveryHistory GROUP BY del_rndfk) b " _
                                & "ON DeliveryHistory.del_rndfk = b.del_rndfk AND DeliveryHistory.del_time = b.Latest " _
                            & "INNER JOIN RunSheetDetails ON DeliveryHistory.del_rndfk = rnd_pk " _
                            & "ORDER BY DeliveryHistory.del_delivered, cus_company, awb_number " _
                    , Null, 0)

    Return Deliveries
End Sub

Any insights?
 

KMatle

Expert
Licensed User
Longtime User
See here: http://www.b4x.com/android/forum/threads/android-process-and-activities-life-cycle.6487/

After a rotation all views/layouts must be loaded/created *new*:

Sub Activity_Create (FirstTime As Boolean)
This sub is called when the activity is created.
The activity is created when the user first launches the application, the device configuration has changed (user rotated the device) and the activity was destroyed, or when the activity was in the background and the OS decided to destroy it in order to free memory.
This sub should be used to load or create the layout (among other uses).
The FirstTime parameter tells us if this is the first time that this activity is created. First time relates to the current process.
You can use FirstTime to run all kinds of initializations related to the process variables.
For example if you have a file with a list of values that you need to read, you can read it if FirstTime is True and store the list as a process variable.
Now we know that this list will be available as long as the process lives and there is no need to reload it even when the activity is recreated.

To summarize, you can test whether FirstTime is True and then initialize process variables.

So load/create them *every time* in Activity_Create (or later when you need it)

Sub Activity_Resume and Sub Activity_Pause (UserClosed As Boolean)
Each time the activity moves from the foreground to the background Activity_Pause is called.
Activity_Pause is also called when the activity is in the foreground and a configuration change occurs (which leads to the activity getting paused and then destroyed).
Activity_Pause is the last place to save important information.
 
Last edited:
Upvote 0

Frank Cazabon

Member
Licensed User
Longtime User
Thanks, that article is what I have based my knowledge on, but things just aren't right at the moment. It's probably something I've done but I just can't see.

Let's take this one issue at a time, so let's deal with the listview that is not showing any items in it when the application starts for the first time.

I have this code (I've cut out the irrelevant bits):

B4X:
Sub Globals
    Private tbhMain As TabHost
    Private lvwRoutes As ListView
    ' other declarations have been left out for illustration
End Sub

Sub Activity_Create(FirstTime As Boolean)
   
    Activity.LoadLayout("MainMenu")

    If ConnectedToLAN.weconnected = "YES" Then
        tbhMain.AddTab("Select Route","SelectRoute")
    End If 
   
    lvwRoutes.Initialize("lvwRoutes")

    If FirstTime Then
   
        If File.Exists(SQLDataBasePath, SQLDateBaseName) = False Then
            'if not, initialize it 
            SQLLite.Initialize(SQLDataBasePath, SQLDateBaseName, True)
            'and create it
            CreateDataBase
        Else
            'if yes, initialize it
            SQLLite.Initialize(SQLDataBasePath, SQLDateBaseName, True)
        End If

    Else
        SetRouteList(lvwRoutes)
    End If
   
End Sub

Sub Activity_Resume
    SetRouteList(lvwRoutes)
    tbhMain.CurrentTab = CurrentPage
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    If UserClosed Then

    Else
        CurrentPage = tbhMain.CurrentTab
    End If
End Sub

Sub SetRouteList (lv As ListView)
    Dim Routes As List
    Routes = DBUtils.ExecuteMemoryTable(SQLLite, "SELECT rte_name FROM Routes", Null, 0)
    lv.Clear
    For i = 0 To Routes.Size - 1
        Dim route() As String
        route = Routes.Get(i)

        lv.AddSingleLine(route(0))
    Next
   
End Sub

I have verified that lvwRoutes has the expected size of 18 at th eend of Activity_Resume, but the list shows as blank.

Does anyone see anything wrong in my logic?
 
Upvote 0

KMatle

Expert
Licensed User
Longtime User
Example:

B4X:
Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim th As TabHost
    Dim lv1 As ListView
    Dim lv2 As ListView
    Dim lv3 As ListView
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")

'I DID NOT LOAD A LAYOUT, SO THE ACTIVITY IS JUST EMPTY :-)    

'Initialize a tabhost and add it to the Activity...
    th.Initialize("")   
    Activity.AddView(th,0,0,100%x,100%y)

'Initialize the 3 ListViews        
    lv1.Initialize("")
    lv2.Initialize("")
    lv3.Initialize("")

'add the 2 Listviews    
    th.AddTab2("ListView 1", lv1)
    th.AddTab2("ListView 2", lv2)
'we forget to add the 3rd ListView ;-)

'fill it
    lv1.AddSingleLine("List #1")
    lv2.AddSingleLine("List #2")
    lv3.AddSingleLine("List #2")

End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub


I just "forgot" to add lv3 so it will not be displayed. Of course it is a valid object which you can fill and do other things with

As you can see, even a rotate works....
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
Is lvwRoutes included in the layout, if so you should not initialize it in the code.
 
Upvote 0

Frank Cazabon

Member
Licensed User
Longtime User
I see "lvwRoutes.Initialize("lvwRoutes")" but it is not added to a view like the tabhost. So it will not be displayed.

Thanks Klaus, lvwRoutes is in the layout so I don't need to add it in in code. It actually displays, the problem is that even though it says its size is 18, it displays blank.

later:
I removed the lvwRoutes.Initialize("lvwRoutes") and the list is now populating and displaying properly!
 
Last edited:
Upvote 0

Frank Cazabon

Member
Licensed User
Longtime User
Are you sure that the text color is not the same as the background color ?

Yes, the list used to show properly, but some change I made in trying to re-factor the code (as I thought I understood things a bit better now) messed it up. It turns out that the initializing of the lvwRoutes was what was causing the problem, but I don't quite understand why :(
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
It turns out that the initializing of the lvwRoutes was what was causing the problem, but I don't quite understand why
If you define a view in the Designer you must NOT initialize it in the code, because this would generate a new instance of the view with the same name.
If you add a view in the code you must Dim it, Initialize it and Add it to a parent view.
 
Upvote 0
Top