Strange, I also have the same result. Don't know if it is limitation or a bug. Recently, I have been using the glovar lavishly (well, it won't run out anyway

). Can't imagine if I don't use map/list, probably I would have hundreds to thousands glovar. So far, I don't put the glovar directly at the Store/Restore Audio Volume. In most of the flows which need glovar map, I would use intermediate variable and later assign it to the map. So here is the method I would use.
WARNING!!! : Prepare yourself for a wall text!!!
1. Storing via direct assignment
I would use the
Store Audio Volumes as example here. But basically you can use to store any kind of variables, especially the one which has some kind of state or values just like the volumes.
For the first time, you don't have glovar yet. You can use script to create it if not exist yet. But since it is a one-time job,
I will just create it manually in the glovar menu (rather than wasting a single line code that never executed anymore), add
global_volume, type
Map. No need to add any value, just press OK. So we create a
blank global_volume with the type
Map, ready to be assigned with value.
Store
For Store Audio Volumes, assign all volume needed to local variables. Example as this.

- 1. Store Audio Volumes local variable.png (70.52 KiB) Viewed 23604 times
After that, you will have collection of intermediate values. Add
Script action after it to assign it to the glovar. It is a simple boring assignment.
Code: Select all
global_volume["alarm"] = alarm;
global_volume["dtmf"] = dtmf;
global_volume["music"] = music;
global_volume["notification"] = notification;
global_volume["ring"] = ring;
global_volume["system"] = system;
global_volume["voice_call"] = voice_call;
global_volume["ringer_mode"] = ringer_mode;
global_volume["interruptions_mode"] = interruptions_mode;
Now the global_volume will be populated with all the value from the volume, mapped each to its correct variable.
Restore
To retrieve the value later in another flow/execution, you can't just use the
global_volume["alarm"] for the same reason. So you have to assign the glovar to intermediate value again. Add
Script first and reverse the value assignment (another boring one).
Code: Select all
alarm = global_volume["alarm"];
dtmf = global_volume["dtmf"];
music = global_volume["music"];
notification = global_volume["notification"];
ring = global_volume["ring"];
system = global_volume["system"];
voice_call = global_volume["voice_call"];
ringer_mode = global_volume["ringer_mode"];
interruptions_mode = global_volume["interruptions_mode"];
Then use the value newly created to the Action
Restore Audio Volumes, use variables alarm, dtmf etc, similar to the
Store Audio Volumes.
This is the most basic method, easy to understand, easy to debug, since you can see the value assignment clearly.
Use this method at the beginning, or when you have key less than 5.
2. Using loop for all keys
As you have more and more key-value in the map, the lines of script for assigning the value keeps getting longer. It started to become annoying. As every addition/removal of key-value pair, you should add/remove it twice, at the storing script and at the restoring script. It can be missed if the flow utilizing it is in different flow or not quite related to each other. (example : you add in the storing script, but forgot to add in the restoring script).
Store
So, we need a way to dynamically assign all value from the map, no matter if we add or remove some key-value from the map. Here comes the loop upon the keys in the map. We can use
getMapKeys() to get all Keys from the glovar map and loop assigning value to it.
Code: Select all
for(i in getMapKeys(global_volume))
global_volume[i] = getValue(i, 0);
Here, we can't just use
[/color] since it will then assign the value only. For first loop,
i = "alarm", so it is just like evaluating
global_volume["alarm"] = "alarm"; //which is wrong.
We must use
getValue(i, 0); as
i = "alarm", it will be evaluated as,
getValue("alarm", 0); which will then evaluated to the volume of alarm (example : 10). The end evaluation is like this
global_volume["alarm"] = alarm; //the correct one, as alarm is 10
Looping all of them will store the corresponding key-value assignment. The 0 just to fulfill the requirement for default value. This
getValue() is part of the dynamic value assignment, you can check more at the index,
creating dynamic variables.
Restore
The restore part is similar, simply reverse the value assignment, and use
setValue() instead.
Code: Select all
for(i in getMapKeys(global_volume))
setValue(i, global_volume[i]);
Same concept here, you can't just use
; for first loop,
i = "alarm", so it is just like evaluating
i = global_volume["alarm"]; // i = 10, not creating new variable alarm = 10
By using setvalue(), i will be evaluated first to "alarm". So the end it is just like
alarm = global_volume["alarm"]; //the correct one, {alarm} will be created
Looping all of them will create variables from all of the keys in the
global_volume.
The catch for this method is you must have the key already. So
global_volume must already have the
alarm, dtmf, music,, etc key inside; so they will appear when using
getMapKeys().

- 2. global_volume.png (42.68 KiB) Viewed 23604 times
You can use the first method to create it, or you can simply add the key directly in Glovar menu, add all the keys you need and leave the value blank.
I usually just create it manually, since it is again the same one-time job.
Use this method when :
- you have to dynamically add/remove key-value pair, so you don't need to think about changing the code everytime you add/remove the variable.
- all values from the glovar only be used/modified in that flow only.
- you have more than 5 key-value pairs. Since you can see that 5 key-value requires 5 lines of script in both store/restore; while using loop for(), you only need 2 lines of script. For less than 5 key-value, just use the first method. Sometimes it is better to be less optimized a bit, for the sake of readability. It is easier to read and understand the code in first method, than the for() loop.
3. Loop only certain keys
As you advance, now you utilize the map not only for single flow, but also for another flows. In certain flow, you only need to use 4 values from the
global_volume (example :
alarm, dtmf, music, notification). Using the method 2, it will store/restore all values in the key list. Depends on the flow, it may cause error; or worse, a logic flaw : wrong value assignment but no error given (
which is more disastrous).
Store
So to only use certain keys, we should create another list to store the keys we need. Then instead of looping using
getMapKeys(), we loop using this list. Adding a
newList() and remember to assign the value exactly as the key as the
global_volume
Code: Select all
voluse = newList("alarm", "dtmf", "music", "notification");
for(i in voluse)
global_volume[i] = getValue(i, 0);
The concept is the same as method 2, but we limit only storing the keys from
voluse.
Restore
Reversing the method, we also use the same
newList() for restore.
Code: Select all
voluse = newList("alarm", "dtmf", "music", "notification");
for(i in voluse)
setValue(i, global_volume[i]);
The catch are you have to type the keys exactly as the keys in the map (sometimes can type wrong) and when adding new keys to include in the loop, you have to add in both store/restore. You can mitigate this by storing the list in another variable, but I think that is not necessary, as if you have reach this stage, usually we don't change the key so frequently (unless you do).
Use this when you have only certain keys needed in certain flow. Probably you have a glovar Map consist of 15 keys and used in 3 separate flows. You can assign the needed keys in each flow using the
voluse.
4. Loop all keys except certain keys
Reversing the idea from method 3, now we need to loop all keys, but only maybe 1 or 2 keys to be excluded. You want all future added/removed keys to be updated just like in method 2, but you also want to exclude certain keys just like in method 3. Example, for this store volume, you want to use all values those has volume, except
ringer_mode and
interruptions_mode. So you want to exclude only these 2 keys.
Store
To do this, from method 3, we should create another
newList() to store the excluded keys.
Code: Select all
volrem = newList("ringer_mode", "interruptions_mode");
voluse = removeAllElementValues(getMapKeys(global_volume), volrem);
for(i in voluse)
global_volume[i] = getValue(i, 0);
The concept derived from method 3, but we reverse the idea.
volrem is used to exclude the keys. We use
getMapKeys() to get all keys from
global_volume, then remove all of the value which are listed in
volrem. The result is
voluse now contains all keys from
global_volume, exclude the ones from
volrem. The we loop the
voluse as usual. Any new added/removed key-value will be always included.
Restore
Reversing the method, we also use the same newList for restore.
Code: Select all
volrem = newList("ringer_mode", "interruptions_mode");
voluse = removeAllElementValues(getMapKeys(global_volume), volrem);
for(i in voluse)
setValue(i, global_volume[i]);
The catch are the same as method 3; type the key exactly and add new exclusion in both store/restore.
Use this when you want to include all keys, except the excluded ones. Probably you have 2 keys to store certain state and time; all other keys added and removed dynamically depends on the need. Change the
volrem to your need.
Test Flow
I purposely created the flow to illustrate the concept above (need automagic 1.34, as I have notes inside) :
flow_Store_Volume_Global_20180204_000000.xml

- 3. Store Volume Global test flow.png (105.17 KiB) Viewed 23604 times
The flow is far from optimized, it has so many duplicated element. I can optimize it, put a input dialog for selection, or combine the script. But that will defeat the purpose of the test flow (so spare me

). I intentionally separate all four methods and add debug dialog so you can check the value directly.
To test the flow, simply connect the trigger to the branch you want to test. Remember to create the global_volume as type Map first in the glovar menu. To test the first method, simply connect the trigger to the left most Store Audio Volume. Check the debug dialog result (
global_volume). Try to change some of your volume slider (alarm, music etc). Then delete the connection, connect now to the script next to it. Check your volume slider, now it has been returned to the state when storing it. You can also see a lot of variable created from the
global_volume.
This is just a test flow for the concept above. You can modify the flow or just utilize the concept in you other flow. There is another way of using the map value to store/restore value, which I use for logging trigger events. But the concept is much wider, and I haven't finish the complement flow to use the value. Maybe I will share in another occassion, after I have finished it.