App Inventor knows only one way of communication between Screens (Android Activity). This is the StartValue at the start of a new Screen and the return value result when closing a screen. Open Screens can not directly exchange data with each other. The extension enables direct communication between screens.
If something is missing, write to me: E-Mail an Ulli.
|1.0 (2021-02-07)||Initial version|
The UrsAI2CommonEvents ZIP archive for download. The archive contains the source code, the compiled binary for uploading to the App Inventor and a sample application.
Note: This extension depends on static variables. It is not usefull to create more than one instance of this extension per Screen.
The functions RaiseEvent# or PostEvent# trigger the OnEvent# event on all open Screens that have integrated an instance of the extension. The easiest way to explain this is with the example included in the download. The sample app (see download) implements an "invisible" Screen1, which provides service functions for Screen2.
"Invisibility" is achieved by opening Screen2 directly at the Screen.OnInitialize event of Screen1. If the app returns from Screen2 to Screen1, the app will be closed immediately. Screen1 is skipped:
Screen1 offers an addition service:
When the event OnEvent1 occurs, the arguments Id and Data are added and sent (returned) via Event1. RaiseEvent# does not trigger the event for the instance of the extension that sends it. Therefore there are no circular calls.
Screen2 increments / decrements the numeric content of a Label with the help of this service:
RaiseEvent# triggers the OnEvent# event immediately. PostEvent# places the order to trigger the event in the message queue. The event is triggered after the current command sequence has been processed. This can also be seen by an example.
Screen1 provides a second service that simply returns the text "From Screen 1":
Screen2 calls up the service via RaiseEvent:
After calling RaiseEvent2, the OnEvent2 event is immediately triggered in Screen1. There RaiseEvent2 is called, which directly triggers OnEvent2 in Screen2. Therefore by OnEvent2 the global variable Value is set before its content is transferred to the Label lblAfter (set lblAfter.text to). lblAfter will display "From Screen 1".
In the second case, the service is called up via PostEvent:
The OnEvent2 event is triggered in Screen1 after the code sequence for the when comPostTest.Click event has been completely processed. lblAfter threfore receives the old value of Value. You can see that the value was changed later, if you look at the value of Value afterwards. The Click event of cmdGetValue is also processed via the message queue and is raised after the OnEvent2 event.
Android / App Inventor puts the Screens / Activities on a stack. The top Screen is the active Screen. It is displayed and receives messages from the user interface.
With Control.Open another Screen a new instance of a Screen class is placed on the stack and becomes the active Screen. Control.Close Screen removes the Screen and destroys it. The Screen below becomes top of the Stack and the active Screen.
Screens that were previously opened, i.e. lower in the stack, are not gone. They just aren't diplayed and won't receive any messages from the user interface. Unfortunately, App Inventor does not offer any possibility to reference these other Screens.
Java offers the possibility of static variables. These are variables that do not belong to an object but to the class. This means that they are equally available to all instances of a class. The extension manages a static list of all created instances of the extension. When an instance is created (constructor), it is added to the list. If the Screen is destroyed (callback function onDestroy) it is deleted from the list.
The functions RaiseEvent# and PostEvent# iterate through this list and trigger the corresponding event on each Screen.
There is still one little thing to consider. The App Inventor class Form, the base for the Screen classes, use a static variable activeForm. A reference to the currently active Screen is kept in this variable. activeform is accessed by many methods.
App Inventor assumes that only Screens at the top of the Activity stack trigger events. When an event is triggered, activeForm is overwritten by the Form that corresponds to component that triggers the event:
Since this extension triggers events that do not come from the active Screen, this variable would get an incorrect value. This is why this variable is saved before the event is triggered and saved back again after it is triggered. activeForm id declared as protected, so Java Reflection is used to acces this field.
Most of the functions of the sample app have already been explained above.
I have collected some tips for creating your own extensions: AI2 FAQ: Developing extensions . On the page you can find further information.
The UML diagrams were created with PlantUML .