Home » Uncategorized » An optimal way to manage multiple windows in App Inventor

An optimal way to manage multiple windows in App Inventor

Introduction

NOTE:

This post was initially published for AppInventor classic, but currently sources are available also for AI2. Unless explicitly noted, comments and images correspond to the classic version but the code is roughly the same.

I have to admit that the method we’re going to explain is not so advantageous in AI2 because now it’s possible to edit several screens at development time, which was one of the two main weak points in AI classic multiscreen. Anyway, the drawback of not being able to share variable and methods remains, and I think that’s enough reason to use this method is most of our projects.

This post demonstrates a method for managing multiple windows in App Inventor based on hiding and showing arrangements from the same screen. I admit the title may be controversial, but I’m really convinced that this is the most effective way to manage multiscreen in the AI current state of art. Anyway I understand this is arguable so if you’re not comfortable with the title just think of this tutorial as an “alternative method to manage multiscreen” which you could consider in some of your apps.

What are we going to build

As we know, release 42 of AI added support for multiscreen, recognizing it as an absolute necessity for any app that goes beyond a simple prototype. So before release 42 we were forced to simulate multicreen by showing and hiding controls. And now I’m proposing to go back to those times (!). Well, let me clarify it. What I’m proposing to do is avoid creating a separate screen for every window you want to show. The reason is that current AI screens have two main drawbacks:

  • You cannot reuse anything among different screens. In other words, you cannot share functions and controls that are common to all screens (you’re forced to replicate them in all the screens). For variables this is somehow mitigated because it’s possible to pass values, but for functions it’s really tedious and a great source of quality problems. We’re still lucky to count on the excellent copier facility provided by the App Inventor Repository, but this helps only when creating the app and not for its further maintenance (which consumes 80% of development time in traditional environments and probably more in AI)
  • You cannot switch forms while testing in the development environment, so it’s not possible to test interaction among screens (you need to generate a version each time)

By including several windows in a single screen we avoid both problems: you can test the windows interaction while developing and you can have a shared version of variables, functions and components that are common to all windows. It has also drawbacks, from which I’d remark two:

  • The design task is more complicated because all the windows are mixed and it’s harder to see the real appearance of each one
  • You have to manage the transitions between screens (particularly the back button)

For the first issue I recommend to mark all windows as non-visible except the one we’re working on. This way we can concentrate successively in the different windows and work in the same conditions as if we were using separate screens. Hidden windows are not a problem for testing because they are appropriately shown by code (as we’re going to see).

Regarding the second issue, that’s precisely why I’ve written this post. We’ll see a method to handle windows transitions in a systematic way. It may appear complex but we must take into account that part of this code would be necessary anyway if we used separate screens. Moreover, it would be replicated in every screen. On the whole, the code for the same app would be considerably longer (I know it very well because the app was initially written with separate screens!).

How it works

The key for simulating the screen transactions is a well known pattern called stack (technically a LIFO stack, which stands for “Last In First Out”). For those who have been around the programming world for some years this pattern leads us back to the hard origins when we were forced to program in machine code primitive computers such as Sinclair Spectrum. The pattern idea is to pile up an undetermined number of events (in our case the windows shown) but at any point in time we need only to be aware of the last event. The solution consists in using an infinite stack (which in AI can be implemented with a list) where we add and remove elements, and maintaining a pointer (a numeric variable in AI) indicating which is the last element from the stack.

This is more clearly shown with an example. Imagine the user logs into the application, pushes the Register button and from here the Help button. Then he presses twice the back button which must bring him back to the login window. The following image depicts the contents of the stack after each event, the red element indicating the currently shown window:

logintutorial_61

As we can see, after pressing the back button we must simply remove the top element and get the new top in order to locate the window to show.

Installation

You can try the application by downloading these sources and uploading them into App Inventor. You’ll realise there’s some functionality that is not explained in this tutorial because this is actually a more general application (which is explained in the Login template post). The part that concerns us is the way to implement seven windows using just two screens.

User interface

Each window to show must be simulated by means of a TableArrangement component. If this kind of arrangement is not suitable for the layout required in our window we can simply add the right arrangement under the TableArrangement. For example, the following image shows a window that requires two arrangements (Horizontal and Table):

logintutorial_62

Therefore our graphical design task consists in distributing each component into the TableArrangement where it must appear. The Arrangements’ Width and Height attributes will typically be set to “Fill parent”.

Code blocks

CONSTANTS

logintutorial_63

  • SCR_LOGIN, SCR_REG, SCR_SEND, SCR_HELP, SCR_GOOGLE, SCR_MAIN: We associate a numeric value to each window in order to make the code more readable (e.g. the sentence “CurrentScreen = SCR_MAIN” is much easier to understand than “CurrentScreen = 1

VARIABLES

logintutorial_64

  • lstStack: List of open windows. This is the stack used to control the back navigation
  • iStackPointer: Pointer to the current screen within lstStack
  • lstScreens: List of TableArrangements used as containers to simulate windows. The fact that all elements in the list have the same type allows to make generic calls to obtain an element and show it, which is the key for the pushScreen, popScreen and ShowScreen auxiliary functions

INITIALZATION FUNCTIONS

logintutorial_65

  • Screen1.Initialize: The only meaningful part is the call to function initScreen and pushScreen. Other sentences are not used in this tutorial
  • initScreen: Initializes the lstScreens variable with the table arrangements used to simulate windows. The order is very important, because the table correspondiing to each window is located by position in this list. For example, to obtain the Register window we must use the sentence:

SELECT LIST ITEM lstScreens, SCR_REG

USAGE FUNCTIONS

The mechanism to open and close windows is as simple as it would be with screens. Here are a couple of examples:

logintutorial_66

  • ButtonRegister.click: Any action that requires opening a window needs just to call the pushScreen function passing as a parameter the constant value assigned to the window
  • Screen1.BackPressed: Call the popScreen in order to remove the top window from the stack and show it. If the stack is empty close the application

Of course for this simplicity to be possible we need the auxiliary functions popScreen, pushScreen and those related.

AUXILIARY FUNCTIONS

logintutorial_67

  • pushScreen: This function receives as a parameter the window to open. It adds the window to the stack, hides the current window and shows the new one using the ShowScreen auxiliary function
  • popScreen: Obtains the window that is on top of the stack and hides it. Then removes it from the stack, obtains the previous one and shows it using the ShowScreen auxiliary function. It returns the currently visible window
  • getCurrentScreen: obtains the screen that’s currently being shown (i.e. the one on top of the stack). This function is called from the initHelp function in order to initialize the help texts taking into account the current window. The function returns directly the iStackPointer value so it does not save space but using a function is smarter and eases evolution in case the stack implementation changes some day

logintutorial_68

  • ShowScreen: This function receives as a parameter the index of the window to show. It then retrieves the associated TableArrangement from the lstScreens list and makes it visible. That’s all regarding the graphical stuff, but this function is also the equivalent to the screen’s Initialize event so it’s the place to handle specific initialization events. In this case:
    • Enable a timer in case we’re showing the Google window (and disable it otherwise)
    • Hide the top bar in case we’re showing the Google or Help window
    • Show the Profile button only in case we’re showing the Main window
  • ShowMain: This function is called to show the main menu. An important aspect to remark is that once in this window the back button is not supposed to go to the previous window but rather to close the application, so the function empties the stack before pushing the Menu window into it.
Advertisements

4 Comments

  1. Camille Y says:

    Hi, I would like to change the order in which the screen appears. In other words, I would like the “tablearrangementmenu” to appear after the user logs in. Also, I would like to add a new table arrangement that would be the home screen when the app is opened and keep the login menu on top. How can I achieve this?

    • eixerits says:

      You can change the initial screen adapting the function ShowMain. You can see the last instruction is “pushScreen(SCR_MAIN)”. If you change it for example by “pushScreen(SCR_LOGIN)” the initial screen will be the login prompt.

      About the second question, you’ll obviously have to start creating the new table arrangement in the design, and then adapt the following in the code blocks:
      – Create a variable SCR_HOME and initialize it to “8”
      – Add your new table arrangement in the initScreens function (at the end of the list)
      – In the showMain function, change the last instruction by pushScreen(SCR_HOME) in order to indicate this is the initial screen
      I think this should be enough, but I don’t know how do you intend to show the menu. For example if this is a button in your home screen, then you’ll have the add an instruction “pushScreen(SCR_MAIN)” in the click event of this button

  2. Archita says:

    How do I verify the email and password for the login part with my data on fusion tables?

    • eixerits says:

      The simplest way is using the Fusiontables component from AppInventor instead of the web component (em>TinywebDB_Login). Then in the ButtonLogin.Click block you’ll have to call the fusiontable’s method Query instead of TinyWebDB_Login.GetValue and finally you’ll have to use the event GotValue from the fusiontable component instead of the TinyWebDB_Login.GetValue (with similar content).
      An alternative solution is to adapt the server component in order to be able to deal with fusiontables. This is a more powerful solution but requires you to be familiar with python. If you’re interested in this solution the post may be a reference.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: