Android Question StateManager subs SaveState() & RestoreState() operating with differing view sequences

Gregg Homan

Member
Licensed User
Anyone familiar with StateManager,

I am enclosing SaveState() log data (see below) and RestoreState() log data (see below) that suggests (to me anyways) that Activity.GetView(i) used within the two StateManager subroutines (see below) is not returning the same exact view each time the Activity cycles through a pause-resume sequence.

I am adding 18 panels with multiple views within each panel to the Activity then I jump from panel to panel by keeping only one panel active at a time with the other panels made inactive. I do not believe that this should cause the SaveState sequence to differ from the RestoreState sequence; but, it does. Am I doing something wrong or is it possible that Activity.GetView(i) is returning a different sequence between SaveState() and RestoreState()? Also, though I don't think it does, could disabling views be a contributing factor?

Thanks,
Gregg

See two For Loops contained in SaveState() & RestoreState(). Note actual error that is throw is shown at the end of RestoreState() log data below.
B4X:
Sub SaveState(Activity As Activity, ActivityName As String)
    If states.IsInitialized = False Then states.Initialize
    Dim list1 As List
    list1.Initialize
    list1.Add(DateTime.Now)
    intSaveCounter = 0
    For i = 0 To Activity.NumberOfViews - 1
        innerSaveState(Activity.GetView(i), list1) '<<<<<<<<<<<< not returning a constant value as within RestoreState()
    Next
    states.Put(ActivityName.ToLowerCase, list1)
    writeStateToFile
End Sub

Sub RestoreState(Activity As Activity, ActivityName As String, ValidPeriodInMinutes As Int) As Boolean
    Try
        loadStateFile
        If states.IsInitialized = False Then
            Return False
        End If
        Dim list1 As List
        list1 = states.Get(ActivityName.ToLowerCase)
        If list1.IsInitialized = False Then Return
        Dim time As Long
        time = list1.Get(0)
        If ValidPeriodInMinutes > 0 AND time + ValidPeriodInMinutes * DateTime.TicksPerMinute < DateTime.Now Then
            Return False
        End If
        listPosition = 0
        IntReadCounter = 0
        For i = 0 To Activity.NumberOfViews - 1
            innerRestoreState(Activity.GetView(i), list1) '<<<<<<<<<<<< not returning a constant value as within SaveState()
        Next
        Return True
    Catch
        Log("Error loading state.")
        Log(LastException.Message)
        Return False
    End Try
End Sub

SaveState log data. The number below represents a sequence counter I inserted into innerSaveState() to help show how the SaveState sequence differ from the following RestoreState sequence.
B4X:
23 Save RadioButton.Checked>
24 Save RadioButton.Checked>
25 Save RadioButton.Checked>
27 Save RadioButton.Checked>
29 Save EditText.Text>
31 Save RadioButton.Checked>
32 Save RadioButton.Checked>
33 Save RadioButton.Checked>
34 Save RadioButton.Checked>
36 Save RadioButton.Checked>
54 Save EditText.Text>
56 Save EditText.Text>
57 Save CheckBox.Checked>
58 Save CheckBox.Checked>
59 Save EditText.Text>
61 Save CheckBox.Checked>
62 Save CheckBox.Checked>
63 Save CheckBox.Checked>
64 Save CheckBox.Checked>
66 Save RadioButton.Checked>
67 Save RadioButton.Checked>
70 Save RadioButton.Checked>
71 Save RadioButton.Checked>
72 Save RadioButton.Checked>
90 Save CheckBox.Checked>
91 Save CheckBox.Checked>
92 Save CheckBox.Checked>
93 Save CheckBox.Checked>
94 Save CheckBox.Checked>
95 Save CheckBox.Checked>
99 Save RadioButton.Checked>
100 Save RadioButton.Checked>
101 Save RadioButton.Checked>
104 Save RadioButton.Checked>
105 Save RadioButton.Checked>
106 Save RadioButton.Checked>
114 Save EditText.Text>
115 Save EditText.Text>
117 Save EditText.Text>
119 Save CheckBox.Checked>
120 Save CheckBox.Checked>
122 Save CheckBox.Checked>
123 Save CheckBox.Checked>
125 Save EditText.Text>
130 Save EditText.Text>
131 Save RadioButton.Checked>
132 Save RadioButton.Checked>
133 Save RadioButton.Checked>
136 Save RadioButton.Checked>
141 Save EditText.Text>
142 Save EditText.Text>
143 Save EditText.Text>
144 Save EditText.Text>
152 Save EditText.Text>
153 Save EditText.Text>
157 Save RadioButton.Checked>
158 Save RadioButton.Checked>
160 Save RadioButton.Checked>
161 Save RadioButton.Checked>
162 Save EditText.Text>
166 Save EditText.Text>
169 Save EditText.Text>
172 Save RadioButton.Checked>
173 Save RadioButton.Checked>
174 Save RadioButton.Checked>
176 Save RadioButton.Checked>
177 Save RadioButton.Checked>

RestoreState log data followed by error. The number (below) represents a sequence counter I inserted into innerRestoreState() to help show how this sequence differs from the above SaveState sequence.
B4X:
18 Read RadioButton.Checked>>
19 Read RadioButton.Checked>>
20 Read RadioButton.Checked>>
22 Read RadioButton.Checked>>
24 Read EditText.Text>>
26 Read RadioButton.Checked>>
27 Read RadioButton.Checked>>
28 Read RadioButton.Checked>>
29 Read RadioButton.Checked>>
31 Read RadioButton.Checked>>
49 Read EditText.Text>>
51 Read EditText.Text>>
52 Read CheckBox.Checked>>
53 Read CheckBox.Checked>>
54 Read EditText.Text>>
56 Read CheckBox.Checked>>
57 Read CheckBox.Checked>>
58 Read CheckBox.Checked>>
59 Read CheckBox.Checked>>
61 Read RadioButton.Checked>>
62 Read RadioButton.Checked>>
65 Read RadioButton.Checked>>
66 Read RadioButton.Checked>>
67 Read RadioButton.Checked>>
88 Read RadioButton.Checked>>
89 Read RadioButton.Checked>>
90 Read RadioButton.Checked>>
93 Read RadioButton.Checked>>
94 Read RadioButton.Checked>>
95 Read RadioButton.Checked>>
103 Read EditText.Text>>
statemanager_innerrestorestate (B4A line: 167) '<<<--- Note this line number is different from original code because of my debugging code
edit.SelectionStart = data(1) '<<<--- Here is the line of code that crashes due to changed sequence
java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
    at ovinion.ovinion.statemanager._innerrestorestate(statemanager.java:170)
    at ovinion.ovinion.statemanager._innerrestorestate(statemanager.java:355)
    at ovinion.ovinion.statemanager._restorestate(statemanager.java:778)
    at ovinion.ovinion.main._activity_create(main.java:639)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:173)
    at ovinion.ovinion.main.afterFirstLayout(main.java:98)
    at ovinion.ovinion.main.access$100(main.java:16)
    at ovinion.ovinion.main$WaitForLayout.run(main.java:76)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5083)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
    at dalvik.system.NativeStart.main(Native Method)
 
Last edited:

Gregg Homan

Member
Licensed User
Erel,

You are right that layout must be rebuilt (prior invoking RestoreState()) exactly as it existed when it was saved by SaveState(). The problem was that I lost track of a panel that contained dynamically generated checkbox views based on user preferences which I have eliminated, and I used a static approach instead. The overhead necessary to rebuild the layout for RestoreState() to process exactly as the layout encountered by SaveState() was more trouble than it was worth. I realize that StateManager as it currently exists depends on RestoreState() and SaveState() processing the same exact layout constructed in identical order for it appears that StateManager has no means of knowing the identities of the views contained by a given Activity. I think I know the answer to the question that I am about to ask because you would have undoubtedly developed StateManager to take advantage of this. But, I'll ask it just the same; is there any way for StateManager to know the identities of the views contained by an Activity so that StateManager is not so sensitive to the construction of the layout encountered by both RestoreState() and SaveState()?

Thanks,
Gregg
 
Upvote 0

Erel

Administrator
Staff member
Licensed User
But, I'll ask it just the same; is there any way for StateManager to know the identities of the views contained by an Activity so that StateManager is not so sensitive to the construction of the layout encountered by both RestoreState() and SaveState()?
If you like you can modify StateManager and instead of writing each view to a file, add its data to a Map where the map keys are the views tags and the values are the current data. You can then store it with KVS or RandomAccessFile.WriteObject. This will solve the order issue.
 
Upvote 0

Gregg Homan

Member
Licensed User
Erel,

Thanks for StateManager modification suggestions which I will consider implementing. BTW, in addition to dynamically generated layouts as I discussed above, I am fairly certain that BringToFront and SendToBack operations can 'innocently' change the layout encountered by RestoreState() and SaveState().

For the sake of helping others avoid problems that I encountered involving StateManager's dependence on the layout remaining constant I invite others to reply to this post with additional 'operations' that might innocently change the layout?

Thanks,
Gregg
 
Upvote 0
Top