Download as pdf or txt
Download as pdf or txt
You are on page 1of 89

Creating Apps

with App Inventor for Android


draft 1, 1/2010
David Wolber
NOTE: This text is under construction-- use at your own risk.
Table of Contents
Chapter 1: Introduction .................................................. 4
Getting Started: Downloading Some Apps .......................... 6
Chapter 2: Building and Deploying an App with App
Inventor ......................................................................... 7
Introduction ................................................................... 7
Building the User Interface ............................................... 7
Programming the App's Behavior....................................... 9
Instant Testing of the App .............................................. 12
Download the App to Your Phone..................................... 12
Chapter 3: An App Is......................................................15
A App is a Recipe .......................................................... 15
An App is a Set of Event-Handlers ................................... 15
An App Consists of Event-Handlers That Can Ask Questions
and Branch................................................................... 17
An App Consists of Event-Handlers That Can Ask Questions,
Branch, and Repeat ....................................................... 18
An App Consists of Event-Handlers That Can Ask Questions,
Branch, Repeat, and Talk to Web Services ........................ 19
An App Consists of Event-Handlers That Can Ask Questions,
Branch, Repeat, Talk to Web Services, and Remember
Things ......................................................................... 20
Chapter 4: Components, Properties, Events, and
Functions.......................................................................22
Components ................................................................. 22
Properties .................................................................... 23
Events ......................................................................... 25
Functions ..................................................................... 25
Summary..................................................................... 27
Problems...................................................................... 28
Chapter 5: Animation.....................................................29
Animated Objects.......................................................... 29
Timer Events ................................................................ 29
Moving an Object Periodically.......................................... 30
Ball/Image Sprite Events................................................ 32
Reacting to Touch and the Ball Reaching an Edge .............. 33
Variables...................................................................... 34
Randomness................................................................. 37
Problems...................................................................... 38
Chapter 6: Conditional Blocks ........................................38
If and Ifelse Blocks........................................................ 39
Sample: Calling a random friend from a set of friends. ....... 41
Sample: Mastermind...................................................... 43
Summary..................................................................... 44
Problems...................................................................... 45
Chapter 6: Lists..............................................................45
Making a List ................................................................ 45
Selecting an Item.......................................................... 46
Using Length of List ....................................................... 47
Iterating Through a List: For Each ................................... 50
Getting Started ............................................................. 53
Example: Quiz App Version 1 .......................................... 53
Iteration 1: Questions and the Next Button. ...................... 54
Iteration 2: Processing Answers ...................................... 58
Summary..................................................................... 58
Problems...................................................................... 58
Chapter 8: Iteration.......................................................61
Computing the Sum of the First Three Numbers ................ 62
Computing the Sum of the first N Numbers....................... 64
A Bug in the Program..................................................... 65
Problems...................................................................... 66
Chapter 9: Web Services, APIs and Mashing Data..........67
Mashups ...................................................................... 71
Tweeting Big Stock Swings To Twitter .............................. 72
RSS............................................................................. 73
Creating Mashups.......................................................... 73
Twitter API ................................................................... 76
An App Inventor Twitter Client for Android........................ 77
Problems...................................................................... 78
Chapter 10: Persistent Data...........................................79
TinyWebDB .................................................................. 81
A Quiz with Multiple Questions ........................................ 84
Programming the Behavior of the "Teacher" Application...... 85
Processing the Entry of New Question-Answer Pairs ........... 87
Summary..................................................................... 88
Problems...................................................................... 88
Appendix A: Setting Up................................................... 0
Chapter 1: Introduction
Programming is like magic to most people, and only a small percentage of
humans ever try it. This is unfortunate, as there are many very creative
people that don't even dream of applying their creativity, at least directly, to
building software. Most people consider the apps they use on their
computers and phones as beyond their control-- they are stuck with being
consumers, and not producers, or even "customizers", of software. The
software we now use would certainly be better if the tools for building it
were accessible to more people.
There has been progress. The web started out as read-only-- only web
masters could create web pages and most of us just "consumed" the
information out there. With blogs, wikis, social networks, and Twitter, the
web has now become a read-write web, and most everybody is now "part of
the conversation".
However, there is still a large chasm in terms of producers and consumers:
though many now blog and create web pages, there are still few who know
how to create apps-- software that displays information dynamically and can
respond to user input and other events. Just as there is a digital divide,
there is also a programmer divide that limits people's control over the
devices they use.
Can this divide be breached? Can ordinary people be taught to program their
computers and their phones? There are reasons to believe they can. Young
people today are incredibly computer literate compared to the previous
generations. They don't fear computing-- it is part of their lives from an
early age. And they use computing hours upon hours a day. Thus, they are
extremely motivated to have useful software and to be able to customize it
for their own personal use.
Google is very interested in this question, and to explore it they have
designed a new visual programming language, App Inventor, designed to
allow people to program their phones. Here is Google's vision:
Mobile applications are triggering a fundamental shift in the way people
experience computing and use mobile phones. Ten years ago, people
"went to the computer" to perform tasks and access the Internet, and
they used a cell phone only to make calls. Today, smartphones let us
carry computing with us, have become central to servicing our
communication and information needs, and have made the web part of
all that we do. Ten years ago, people's use of computing was largely
dissociated from real life. With the ubiquity of social networking, online
and offline life are becoming fused. (Our) exploration is motivated by
the vision that open mobile platforms like Android can bring some of
that same change to introductory Computer Science, to make it more
about people and their interactions with others and with the world
around them. It's a vision where young peopleand everyonecan
engage the world of mobile services and applications as creators, not
just consumers. Through this work, we hope to do the following:
Make mobile application development accessible to anyone.
Enhance introductory learning experiences in computing through the
vehicle of Androids open platform.
Encourage a community of faculty and students to share material and
ideas for teaching and exploring.
From Google Research Blog:
http://googleresearch.blogspot.com/2009/07/app-inventor-for-android.html
The App Inventor visual language makes developing Android apps
considerably easier than with a traditional programming language. With App
Inventor, everything you can do is visible, and you program by piecing
together blocks representing phone functionality and data. It is similar to
the Mindstorms blocks language for programming Lego robots, and the
Scratch language for creating web animations, but you program your phone
instead.
The key from a learning perspective is motivation: people are
significantly more motivated to learn programming and computer concepts
because they are building something fun that they can use in their every day
life. In teaching App Inventor, I've been amazed at how hard students have
worked-- their motivation level has been significantly higher even any
beginning course I've ever taught. My belief is that they are more motivated
because they are building "real" software-- software that can benefit their
everyday lives.
This book steps you through the process of building Android apps using App
Inventor. We'll begin with some simple apps-- an app that speaks what you
type, and an app that moves a ball around the screen. But rather quickly
we'll progress to more complicated apps and you'll be building games,
educational software, Twitter clients, and maybe even the next killer app for
the Android platform!
Getting Started: Downloading Some Apps
The Market
The Android Market has thousands of apps, many of which are free to
download. You can search for specific keywords to find an app, and you can
read a blurb about the app and see reviews of it before downloading. Before
embarking on our journey to learn programming, definitely download some
apps and become acquainted with how Android apps look and behave.
Barcode Scanner
There are two specific apps that we'll use in the programming lessons. The
first is a barcode scanner. This is required because when you build an app,
App Inventor creates a barcode for the app. With an Android barcode scaner,
you can scan the barcode in order to install the new app on your phone.
Very cool!
One popular barcode scanner is from ZXing. If you go to the Market and
search for it, you'll find it. Just step through the installation instructions and
you'll have a barcode scanner. For fun, try scanning the ISBN barcodes of
some books to see what the scanner does with them.
Text To Speech
The first sample app we'll create will speak the words the user types. For
this, you need to have Text to Speech (TTS) library code on your phone.
With TTS, your apps can speak words that have been typed in or sent as a
text to your phone. You can download a TTS app named TTS Service
Extended at the Android Market.
Once you've downloaded it, open the app and click on menu to choose a
Default Engine. If you don't choose an engine, the app won't work (there's
no default setting unfortunately). You can also change the default language
and speech rate.
Once you've installed it, test it by clicking on the App to start it, then clicking
menu and choosing "Listen to a preview". Then try changing to a different
language to see what happens.
Chapter 2: Building and Deploying
an App with App Inventor
This chapter describes App Inventor and steps through the task of creating,
testing, and deploying a mobile app.
Introduction
Programming in App Inventor is a two-step process: you first design the
user interface for the app-- how it will look, then you design how the
application will behave.
These two tasks are performed in separate windows. The first window is the
Component Designer. You use it to choose and place the buttons, text
boxes, images, and other components that will appear on the phone when
your app is run. The second window is the Blocks Editor. You use it to define
the behavior of your app-- how it should respond to events such as the user
pressing a button.
Building the User Interface
We'll start with a simple example: an application that let's the user enter
some words, then speaks the words when the user clicks a button. Though
simple, this application illustrates the basics of App Inventor and the basic
structure of a mobile app.
To build the application, first open the component designer:
The left side palette has all the components that can potentially be added to
an application. The left-middle panel is the surface representing the way the
phone's screen will appear when the application runs. The programmer
drags from the left to the left-middle to specify the components of a
particular application.
For the sample app, you'll need three components: a TextBox where the
user can enter the words she wants spoken, a button for the user to click,
and a TextToSpeech component that will do the work of actually speaking
the words.
The TextBox and the Button are part of the Basic palette, which is open in
the snapshot above. There are a number of other component palettes. The
TextToSpeech component is found in palette named Other Stuff.
The TextToSpeech component is a "non-visible" component, meaning it
won't appear on the phone's screen when the app runs. You can think of it
as a little man deep within the phone who will speak out the words the user
types, but will stay hidden from view.
As a component is dragged into an app, it's name appears in the middle-
right list of components. By default each component is given a name that
includes its type and a number (e.g., 'TextBox1'). You can select a
component to change its name and modify its properties. The name is
important because when you begin programming the behavior of the app, in
the Blocks Editor, you'll need to refer to particular components by name.
The component designer is used only to specify the way the application will
look (it's presentation). If you download the app we've developed thus far, it
will look fine but nothing will happen when the user types text and clicks on
the "Speak It" button.
Programming the App's Behavior
Click on the Open Blocks Editor button in the Designer menu to begin
programming the behavior of the application.
If you were writing a traditional computer program, you would type code
using a programming language like Python or Java at this point. With App
Inventor, you program the app's behavior by configuring pre-defined blocks.
The Blocks Editor provides you with two palettes from which you can drag
blocks, the Built-in pallete and the My Blocks palette. The Built-In palette,
shown in the picture above, provides general programming blocks you'll
need to specify the behavior and logic of the app. We'll explore these later.
The My Blocks palette:
has blocks representing the components of your particular application, the
ones you added in the Component Designer. This example shows four
components: Screen1, which represents the entire screen of the app,
SpeakItButton, TextBox1, and TextToSpeech1. Each of these components
has a drawer containing function and property blocks for the component.
There is also a My Definitions component for custom variables and functions
you define.
When you click on a component, say the SpeakItButton, you can see all of
the events and functions associated with it:
Each component's drawer contains blocks associated with the component,
including events, properties, and functions.
The pink blocks at the top represent events that can occur which are related
to the component. As the snapshot shows, a button component like
SpeakItButton has three associated events: when the user clicks it, when
the user touches it or in some other manner gives it focus (Got Focus), and
when it loses focus (LostFocus).
For the simple 'type in some words and click to speak them' example, you'll
first choose the SpeakItButton.Click event and drag it into the program block
area:
This event-block can be read as, "when the user clicks on SpeakItButton, do
..." Until you drag in some operations and place them within this event
block, nothing will happen when the app runs and the user clicks the button.
In this case, the application should respond to the click by getting the text
the end-user has entered and giving it to the TextToSpeech component. If
you click on the TextToSpeech1 component's drawer, you'll see it has a
number of operations including one named "Speak".
This block will cause the phone to speak a message. It has one argument
(slot) named message. Whatever you plug into that slot will be spoken. For
this app, you want the message to be the text that was entered by the user
in the textbox named TextBox1. That is, you must envision that the user has
typed in some words in the text box and then clicked on the SpeakIt button.
You can access the words entered by user by opening the TextBox1 drawer
and finding its "Text" property. This "Text" property is a memory cell within
the component whose job is to store what the user types. With this property,
you can complete the behavior:
TextBox1.Text -- what the user has typed -- is hooked in as the "message"
of the function TextToSpeech1.Speak. Both of these blocks are placed within
the SpeakItButton.Click block.
In programming, we call such a when-do block, along with the operations
inside it, an event-handler. In this sample, the event handler has only one
operation (block), but in general an event can invoke many operations.
The event-handler reads as "When SpeakItButton is clicked, TextToSpeech1
should speak the message that is the text entered by the end-user in
TextBox1.
Instant Testing of the App
You can instantly test the apps you create, as you're creating them! If you
have an Android phone, just plug it in to your computer using a USB port.
Then in the Blocks Editor, select "Connect to Phone". Within 30 seconds or
so, you should see your app running on the phone.
If you don't have a phone, you can test most apps using an Android
emulator. For instructions on installing and running an emulator, see
http://www.appinventor.org/android-emulator.
Download the App to Your Phone
Instant testing is great for development, but when you unplug the phone the
app isn't really downloaded on the phone. Thus, when you complete a
version of your app that you want to really use or share, you need to
download it to the phone. One way to download an app is by scanning a
barcode.
Back in the Component Designer, select Package For Phone | Show Barcode:
After a minute, a barcode will appear on the screen:
You'll need a barcode scanner on your phone-- you can download the ZXing
Barcode scanner from the Android Marketplace if you don't have one. Once
you have it, start it up and place the barcode scanner's window so that the
barcode on your computer appears within it. When the phone reads the
barcode, it will step you through downloading and installing your app to the
phone.
When you run the application, it will look like this:
When you, the end-user, enter some words and press "Speak It", the words
will be spoken.
Chapter 3: An App Is...
This chapter is conceptual: we examine the structure of an app, beginning
with the analogy that an app is like a recipe. You will learn about event-
handlers, conditionals, and repeat loops, and be ready to delve into some
more complicated Android programming.
A App is a Recipe
The simplest computer programs are like recipes: the app specifies the
computer instructions that should be performed: do A then B then C:
An App is a Set of Event-Handlers
Mobile and web apps don't really fit the recipe paradigm, as they have
graphical user interfaces (GUIs) with which the user interacts. Such apps are
better described as a set of event-handlers, with multiple recipes that are
only performed in response to some event.
Events are often user initiated: the user clicking a button or choosing an
item from a drop-down list. The "recipe" performed in response can be one
or more of the functions that the computer or phone is capable of
performing. The event and the functions executed in response to it are
together an event-handler.
Most apps will have many event-handlers: In Chapter 2, we described an
application which could be described with a single event-handler:
The app responded only to the SpeakItbutton.Click event, and it responded
by getting the text from the component TextBox1 (the text the user had
entered) and calling the TextToSpeech.Speak function with that text.
App Inventor is a language based on the event-handler paradigm.
Conceptually, nothing happens except in response to an event. You'll never
drag in function blocks into the app area without hooking them into an
event's "when-do" block. For instance, you wouldn't want blocks like:
floating in the block editor outside of an event-handler.
Okay, you're saying, I get the event-handler paradigm, but aren't there
actions that should be performed when an app runs, without waiting for an
event?
The answer is 'yes'. For instance, a Twitter client for Android might need to
contact the Twitter web service to get the user's information as soon as the
app begins. With App Inventor, these fit into the event-handler paradigm
through the use of the Screen.Initialize block. If you want to do X when an
app starts, you can plug X onto the Screen.Initialize block. For instance, you
could have an app welcome the user on startup:
There is also a special Timer component that allows you to trigger responses
when a certain amount of time passes. So an app with a moving object is
characterized as an app with a timer event where the response to the event
is to move the object.
Events types include user-initiated events like button clicks, initialization
events, timer events, and external events such as the phone receiving a text
or information from a web service like Twitter arriving to the phone.
The job of the app programmer, then, is to put together blocks that say how
the phone should respond to all pertinent events.
An App Consists of Event-Handlers That Can Ask Questions and
Branch
Many responses to events are not linear recipes, but contain branches and
loops. The app is allowed to ask questions -- to query the data within it--
and determine its course based on the answers. We say that such apps have
conditional branches:
Here, when the event occurs, we perform operation A, then only perform B1
if some condition is true. If the condition is false, we instead perform B2.
Once either of the branches completes, the app proceeds back on the main
branch (C).
Conditions are questions such as "has the score reached 100?" or "did the
text I just received come from Joe". Such examples are simple; in general,
you can code any complex logic with nested conditionals and various
comparative operators.
To check conditions in App Inventor, you'll use "if-then" blocks and "if-then-
else" blocks:
You can insert any type of condition in the test slot. If its true, the blocks
within the then-do are executed (B1 in the previous diagram). If it is false,
the blocks within the else-do are executed (B2 in the previous diagram).
An App Consists of Event-Handlers That Can Ask
Questions, Branch, and Repeat
Besides asking questions and branching based on the answer, you can also
branch up in a app so as to repeat some operations multiple times. Such an
up-branch is called a loop and can be characterized with the following
diagram:
The operation A is executed, then a condition is checked. If it is true, B is
executed. Each time B is executed, the app jumps back up and checks the
condition again. This loop is repeated until the condition becomes false.
App Inventor provides two "repeat" blocks, the while-do and the foreach.
With the while-do, the condition is put into the test slot, and the operations
to repeat are put in the do slot.
The foreach is specifically for repeating operations on a list of data.
An example of an app that uses a repeat is one that texts a list of phone
numbers. The condition in such an app is "am I at the end of the list of
numbers?" and the operation is sending the message to the current person
in the list.
An App Consists of Event-Handlers That Can Ask
Questions, Branch, Repeat, and Talk to Web Services
Some apps use only the information within the device they are running on,
whether that device be a phone or a computer. But many apps communicate
with the outside world by sending requests to web services.
Twitter is an example of a web service that an App Inventor app can talk to
You'll write apps that communicate with Twitter both to gather data to
display on the phone, and to update your Twitter status. Apps that talk to
more than one web service are called mashups, and we'll explore those as
well.
Web services like Twitter provide an application programmer interface (API),
which is the protocol for how a program communicates with the service.
We'll discuss web services and APIs extensively in Chapter 6.
An App Consists of Event-Handlers That Can Ask
Questions, Branch, Repeat, Talk to Web Services, and
Remember Things
When you use apps, you expect them to remember things for you, such as
the contacts you enter into your contact manager app. Such memory that
lives even after an app is closed is called persistent data and is stored in
some type of a database:
App Inventor provides persistent memory in two ways. The TinyDB
component allows you to store data persistently directly on the phone. The
TinyWebDB component allows you to store data on the web, and thus share
the data with other phones and apps. We'll explore the use of both of these
database components and build apps such as a quiz application that lets the
teacher create and maintain the list of questions.
Summary
A programmer must view an app both from an end-user perspective and
from the inside-out. With App Inventor, you'll design how an app looks and
then you'll design its behavior-- the set of event-handlers that lead an app
to behave as you want. You'll build these event-handlers by assembling and
configuring blocks representing events, operations, conditional branches,
repeat loops, web service operations, and database operations, then testing
your constructions by actually running the app on your phone. After writing
a few programs, the mapping between the internal view of an app and its
physical manifestation will become clear. When that happens, you will be a
programmer!
Chapter 4: Components,
Properties, Events, and Functions
In this chapter, you'll learn about components and modifying their
properties, as well as more on programming the event-handlers of an
application. You'll begin with a simple app that just draws a circle when a
button is clicked, then progress to an app for painting pictures on your
phone.
Components
The items that appear on the phone when an app is running-- text, input
boxes, list boxes, graphics, drawing canvases, etc.-- are called components.
There are also non-visible components representing things like motion
sensors and the Twitter web service.
The components that you can add to an App Inventor app are organized into
palettes that run along the left side of the designer:
The "Basic" palette has the most common
components. Button, Label, and TextBox are
probably the most popular: the label
component is for text the user can't modify,
the TextBox is used to get input from the end-
user. The Checkbox and ListPicker are for
allowing the user to choose between options.
The canvas and image are used for graphical
apps like paint programs and games. The
Clock if for timer events while TinyWebDB is
for storing data in a database.
The other palettes have more application-
specific components: Media is for playing
sounds and movies; Animation provides an
image sprite that can move around a canvas.
Social provides components for making phone
calls, texts, and accessing Twitter; Sensors
provide components for sensing the location
and movement of the phone; Screen
arangement components are for beautifying
the user interface.
Other stuff and Not ready for prime time have
assorted components: highlights include the
TextToSpeech component, the TinyWebDB
component for storing data in a web database,
and ActivityStarter for launching any Android
app from your app.
Properties
All components have a name and properties-- the information that defines
the component. The name is how the component is referenced in the Blocks
Editor-- thus it is important to name the component well with a specific
name (and often with a suffix that identifies its type, e.g., Button).
A visual component has properties such as width, height, and background
image, any text associated with it, and whether it is enabled or not.
The snapshot to the left
shows the properties for the
SpeakItButton. In the
snapshot, the button
component is selected in the
Components pane, so it's
properties appear in the
Properties window.
A Button component has
some properties common to
many components. Its Text
property appears on the
button, and its BackGround
Color or Image appears on
the button as well.
Another common component
is the Canvas. It defines a screen sub-area on which the user can draw,
paint, and manipulate images. Like the Button component, Canvas has a
Width property. Often, the width of a canvas will be set to "Fill parent..."
which means the canvas should span the width of its parent, which is the
screen itself. A height of 400 pixels will take most of the phone's screen.
Because canvas components allow users to paint on them, they have a
PaintColor property. This property specifies the color of any end-user
painting that might occur.
It is important to note that component properties can be set in the
Component Designer and in the behavior editor. In the designer, you are
setting the initial value of a property-- when the app starts, the properties
are set with these initial values. In the behavior editor, you can specify
changes to properties that should occur in response to an event. You'll do
this by adding a block to set a property within some event handler. For
example, if you wanted to change the canvas PaintColor when a user clicked
a button, you could have an event-hanlder like the following:
Events
Besides having properties that define its state, each component also has a
set of events that the component can respond to. A component's events only
appear in the Behavior editor, at the top of the component's drawer.
User actions like a button click are the most common type of event. But
there are other types as well:
Timer events-- The passing of time can trigger an event.
Sensor events-- a change in phone location can trigger a location
change event. The phone has an accelerometer which triggers motion
events.
Phone events-- when a call or text come in it can trigger an event.
Communication events-- when your app requests data from a web
service, an event will be triggered when that data is received.
Functions
Besides having properties and events that it responds to, a component also
has functions that can be applied to it. All components have functions to
change and get the value of each of it's properties. Above, we showed how a
set function could be used to set the value of the PaintColor property of a
canvas.
Most components also have other functions associated with them. For
instance, the Canvas component, besides it property set-get functions, also
has the following: DrawCircle, DrawLine, DrawPoint, and Clear.
If, in response to a button click, you wanted to draw a circle on the canvas,
you'd specify it by dragging in the DrawCircle function and placing it in the
Button.Click event handler:
As you can see from the DrawCircle block, the function has three open slots
labeled x, y, and r. These slots are called parameters (they're also known as
arguments). A parameter is a piece of information that the function needs to
do its job. If you told a child to draw a circle on the paper, the child might
ask you: where on the paper and how big? This is the information that is
needed to DrawCircle, and in App Inventor the where of a circle is specified
with x and y coordinates, and the size with the radius r, all measured in
screen pixels (the size of one tiny dot on the screen).
If you left the x, y, and r slots empty, your app would not work-- parameters
(slots) must be filled in. So After dragging the DrawCircle operation onto the
program area, the programmer must specify actual values for the
parameters. Above the blocks, there is a mini-palette of programming
components. In this case, you would click on the one labeled Math and
chooses a "123" block that represents a number. The number block can then
be placed into the slot for x with a number, say 20, entered instead of the
"123". Similar blocks can then be added for y and r:
The x and y coordinates are in relation to the top-left of the screen, with x
larger as you go right, and y larger as you go down:
x=0,y=0 ........... x=300,y=0
x=1,y=1
.
.
.
x=300,y=300
Now since pixels are very small, there are actually hundreds of pixels
running across the width and the height of the phone. So if you ran this app
and clicked on the button, a circle would be drawn at x=20,y=20, which is
near the top-left corner:
Summary
This chapter described the basic-building blocks of an app. Apps consist of
components, both visual and non-visual. Each component has properties
that track of the current state of the component, things such as its width
and height.
Each component also has a set of events and functions associated with its
dynamic behavior. Events are user actions and other actions that the
component responds to, e.g., a button responds to a user clicking it.
Functions are things that can happen to a component and often change its
state. For instance, the DrawCircle function modifies the state of a canvas
component by drawing a circle on it. DrawCircle, like most functions, has
parameters associated with it. When invoking a function on a component,
the programmer must specify these parameters so that the function knows
how to do its job (e.g., how big to draw the circle).
Problems
1. Program an application that draws a circle in the center of a canvas when
a button is clicked.
2. SaveAs your DrawCircle app into another app and name it CanvasFun.
Modify the program so that:
The canvas has an image as a background. You can set this in the
component designer.
The user can click on a second button to draw a green circle at 40,40.
Note that you'll need to set the PaintColor property of the canvas in
the Click event handlers of both buttons.
The user can click on a third button to clear the canvas. You'll need to
use the Canvas.clear block.
3. Program the PaintPot painting app from Google:
http://sites.google.com/site/appinventorhelp/tutorials/paintpot
Chapter 5: Animation
In this chapter, you'll learn how to write a simple animated game and be
introduced to timer events, randomness, and global variables.
Animated Objects
App Inventor has two types of animated objects: a Ball and an ImageSprite.
A Ball has a restricted appearance, while an ImageSprite is any image you
load.
Timer Events
Many of the events that occur in a mobile phone app are end-user initiated,
e.g., the user clicks a button. There are other types of events as well,
including the Timer event, which is triggered not by the user but by the
passing of time.
To add a timer event, you first add a Clock component to the application in
the Component Designer. Think of the Clock component as a tiny alarm
clock inside your app. You drag it in from the Basic palette, and it is
automatically placed in the 'non-visible component' area, as its not
something that will appear on screen.
One important property of the Clock component is its interval. The interval is
in milliseconds (1/1000 of a second). If you set the interval to 1000, then a
timer event will be triggered every second.
Moving an Object Periodically
To illustrate use of the timer, let's consider the most fundamental animation:
moving an object across the screen at a consistent pace. Specifically, we'll
develop an app in which the the ball move horizontally across the screen at
10 pixels a second.
In the Component Designer, drag in a canvas onto the screen, then a ball
onto the canvas. The canvas is in the basic palette, while the Ball is in the
Animation palette (along with the Image Sprite). A canvas is required for
any animation: you cannot add a ball or image sprite directly on the screen.
After defining the components, open the Blocks Editor, then open the Clock1
drawer within My Blocks. Drag in a Clock1.Timer event to specify the activity
that should occur on each timer interval:
Since the interval for the Clock1 component is set to 1000 milliseconds, the
blocks we put into the Clock1.Timer event will be repeated every second.
In our case, we want to move the ball across the screen 10 pixels every
second. So we'll open up the palette for Ball1, and drag in a Ball1.MoveTo
operation:
MoveTo moves the ball to a specific place on the canvas, specified with the x
and y parameters. How can this operation be used to move the ball right 10
pixels?
Well, another way to characterize, "move the ball right 10 pixels' is, "change
the ball's x property so that it is 10 more than what it was, and keep its y
coordinate the same." To do this, we'll need to make use of a built-in +
block from the Math drawer:
The + block has two slots for its operands. We want to add 10 to Ball1's X
property, so we open Ball1's drawer and drag in the X property, then open
the Math drawer and drag in a number block, entering 10 as the number.
We then slot in the Ball1.X and number 10 into the + block, and the whole +
block into the x parameter of the MoveTo block. Finally, to keep the Y
property the same, we drag in a Ball1.Y block and place it into the y slot of
the MoveTo block. Here's the resulting event-handler:
The blocks read, "On every timer interval, change the x property of the ball
to 10 more than it was and leave the y value the same". Because the
interval of Clock1 is set to 1000 milliseconds (one second), the ball will move
right ten pixels a second.
Using this same scheme, any type of motion is possible. Can you write an
app that moves the ball vertically? from bottom to top? Diagonally? All of
these can be programmed by setting the initial location of the ball in the
component designer, then correctly setting the parameters of the MoveTo.
Ball/Image Sprite Events
Both Ball and ImageSprite have a number of events that they respond to:
Touched is triggered when the user touches an object on the screen. If the
user then drags his finger along the screen, a sequence of Dragged events
are triggered. Dragged is the key event of paint programs.
EdgeReached is triggered when an object reaches the edge of its enclosing
canvas. Say the canvas has a width of 400 and a height of 300. Then
EdgeReached is triggered when 1) the object's X property is less than 1 or
more than 400, or 2) the object's Y property is less than 1 or more than
300.
CollidedWith is triggered when when an object runs into another. The
parameter other1 tells you which other object is involved.
NoLongerCollidingWith is triggered when two objects that were touching are
no longer in contact.
Reacting to Touch and the Ball Reaching an Edge
To illustrate some of the Ball/Image events, consider an app which 1) moves
the ball to the center of the screen when the user touches it, and 2) moves
the ball to the left-side of the canvas when it reaches an edge.
The first event-handler reacts to the Touched event. Since we want the ball
to move to the center of the canvas on the touch, we'll need to use the
Canvas.Width property as well as a division block from the Math drawer:
The x parameter of the MoveTo is set to 1/2 of the canvas's width. We leave
the y parameter (the vertical location) the same.
The second event-handler reacts to the EdgeReached event. For this event-
handler, we just set the x parameter of MoveTo to 1:
With these event-handlers, the ball will move across the screen until it
reaches the right-side, at which time it will appear again on the left. If the
user touches the ball, it will move to the middle of the screen.
Variables
In programming, the term variable refers to a named memory cell. It is a
place in the phone's memory where you can store a specific data item.
These memory cells can be accessed by an app, but they are not directly
visible to the end-user of the app.
We've already considered one type of variable-- the properties of a
component. As we've seen, these variables have names of the form:
component.property
For instance, in the last chapter we worked with the PaintColor property of
the Canvas component, Canvas.PaintColor. This is just a memory cell with a
color in it. When the canvas draws something, it checks that memory cell to
see what color to draw.
In App Inventor, you can also define variables that are not associated to a
particular component. Such variables are called global variables. For
instance, in many games, you'll need to keep track of the score, so you'll
define a global variable named "score". Later, we'll also discuss global
variables which are not single numbers but lists of data, and that allow you
to remember things like the questions of a quiz.
You define new variables by dragging out a "def variable" from the Definition
drawer of the Built-In palette:
After dragging in the block, you should rename the variable (its default
name is "variable"). To rename it, click on the word variable and type the
new name.
You should also initialize the variable. If its a text or number, just click on
the red ? block, choose text or number, and specify the particular value. For
a
variable to track the score of a game, you'd name it "score" and connect a
number to it with an initial setting of 0:
The result of these blocks is to set up a new memory cell within the phone's
memory, and put a 0 in it.
Phone's memory...
score
0
When you define a variable, App Inventor adds blocks for looking at
(getting) and modifying (setting) its value in the My Definitions drawer of My
Blocks:
The first block, labeled "global score" allows an app to access the value of a
variable. For instance, you could display the score in a Label Component
with:
If there was a 0 in the hidden memory cell of score, 0 would be displayed to
the end-user in the label component named ScoreLabel.
The block labeled "set global score to" changes the value in the memory cell.
For instance, the following:
would change the value in score to one more than it's current value. If it was
0, it would change to 1, 1 to 2, and so on.
In programming, such blocks are called assignment statements, which can
be confusing for beginning programmers. The key is that the right-side of
the block sequence is evaluated first. The app will first evaluate the
expression on the right side by grabbing the value of score and adding one
to it. The result is then placed back into the variable score (due to the set
global score block).
With a variable score, we can extend the ball animation app above so each
time the end-user touches the ball, five points are added to the score.
Each time the ball is touched, the app moves the ball to the middle of the
screen, then adds one to the variable score.
Unfortunately, score is a variable, so it is hidden from the user of the app
unless you display it in a label or other user interface component. So go
back to the Component Designer and add a ScoreLabel to the interface.
Then modify the Ball1.Touched event-handler to update the ScoreLabel:
Randomness
Computers can generate random numbers, typically using the computer's
real-time clock to seed the generation of the numbers. Such random number
generation is essential to many games. For instance, the game Mastermind
generates a random sequence of colors for every game. The game
WhacAMole moves the mole to random spots on the screen.
App Inventor provides a number of blocks for adding randomness to an
application. They appear in the Math drawer of the built-in palette:
To write an application that displays a number between one and ten, you
could use the random-integer block:
The random-fraction block returns a decimal number between 0 and 1. Say
you wanted to modify the ball animation so that when the ball reaches the
right edge, it jumps to a random column on the canvas, instead of the first
column. To implement this, you'd multiply a random-fraction block with the
width of the canvas:
If the canvas was 400 pixels wide, and the random-fraction function
happened to return 0.5, the ball would jump to the middle. If the random-
fraction function returned .1, the ball would jump to 40 pixels from the left
edge.
Problems
Write the following programs and document them on your portfolio:
1. Program a ball animation "BallAnimation" application such that:
The ball moves diagonally from top-left to bottom-right of the canvas
at a rate of 20 pixels per second.
When the ball reaches an edge, it appears again in the top-left of the
canvas.
When the user touches the ball, it is sent to the middle of the canvas.
2. SaveAs BallAnimation into "BallAnimationScore" and:
Modify the application so that it keeps score of the number of times
the end-user touches the ball. Use a global variable to do it.
Modify the application so that when the ball reaches the edge, it
jumps to a random column and row on the canvas.
3. Create the game WhacAMole, following the Google tutorial at
http://sites.google.com/site/appinventorhelp/tutorials/whackamole. Call
yours WhackAnX where X is someone you'd like to whack (use their image).
Chapter 6: Conditional Blocks
This chapter discusses apps that branch to execute different functions based
on some condition.
Most interesting apps consist of event-handlers that are not linear recipes,
but contain conditional branches and repeat loops. We discussed the for-
each repeat block in chapter 6 and how an app can continually branch up in
the code to execute some functions over an entire list of data. Such code
might be described as "perform this function n times, where n is the number
of items in the list".
We can also define event-handlers that perform a function 0 or 1 time,
based on some boolean condition. Such event-handlers can be described
with the following flow chart:
Here, when the event occurs, we execute operation A, then only execute
action B1 if some condition is true. If the condition is false, we execute B2.
Conditions are questions such as "has the score reached 100?" or "is a
random number 1 or 2". Such examples are simple; in general, you can
code any complex logic with nested if-else conditions and various logical
operators.
If and Ifelse Blocks
Control blocks allow you to put conditional branches and loops into the
event-handlers of your App Studio program. You'll find such blocks in the
Control drawer of the built-in palette:
Let's first look at an simple example where we set the text of a label to "You
win" when a score reaches 100.
The first thing we do is to drag an if-then-do block into the program area.
Then we build a condition to plug into the "test" slot.
Conditions are boolean, meaning they return a result of true or false. They
generally test the value of properties and variables using the following
logical operators:
These operators can be found in the Math and Logic drawers.
For our sample, we'll drag in an = block:
The condition we want to check is "is the variable score equal to 100".
Assuming we've already defined the variable score, we can find a block for it
in the My Program drawer of My Blocks. We use a number for the 100. We
stick those two items into the slots of the =, and the whole = block into the
slot of the if-then-do:
If the test evaluates as true, we want to tell the end-user they've won:
Note that if the test is false (score not equal to 100), the action within the if-
then block doesn't happen. In fact, nothing happens. If you want a false test
to trigger an action, you can use an if-then-else block.
Sample: Calling a random friend from a set of friends.
Suppose you wanted an application you could use when you were bored--
you press a button and a random friend is called. You could use a random-
integer block to randomize the selection, then an if-then-else block to set
the phone number to one of the choices:
In the above sample, we use a global variable RandomNum to hold the
random number returned from the random-integer function. This number
will be 1 or 2 based on the from and to arguments given.
After setting randomNum to either 1 or 2, we compare it to the number 1 in
the ifelse test. If the randomly generated number is 1, we set the phone
number to 3779199. If it is not 1, the ifelse test is false, so the else-do
blocks are executed and the PhoneNumber is set to 3594787.
If we wanted to choose between more than two numbers, we'd place an if-
then or if-then else within else clause of the first if-else:
If the first test is true, the first then-do branch will be executed. If it is false,
then the else branch is executed, which immediately runs another test. So if
the first test is false, and the second true, the second then-do is executed. If
both tests are false, the else-do branch at the bottom is executed, and the
third number (2423428) is called.
Note that this modification only works because we also modified the to
parameter of the random integer so that a number between 1 and 3 is
generated.
When one control construct is placed within another, we say it is nested.
We'd say that the event-handler above has a "nested if-else". By using
multiple levels of nested if-else blocks we can write app behaviors that
choose between n choices, instead of just two or three.
Sample: Mastermind
Mastermind is a great thinking game. There are many on-line versions of it,
including the one at http://www.irt.org/games/js/mind/. The game (app)
generates a "secret code" of four colors. The player then continually tries to
guess the code, receiving feedback on each of the guesses. The feedback
tells the player how many colors are in the right position (exact matches)
and how many are the right color but in the wrong position (partial
matches).
Let's build an Android version of this app. In the process, will make use of
some of the conditional (if-else) and iterative (foreach) blocks we've been
discussing.
Iteration 1: Toggling through colors
It's always a good idea to start with something simple, then build on
complexity. We'll start with some simple functionality. Let the user choose
between three colors by clicking a button. On each click, the button should
change to the next color in the sequence, and when it reaches the third
(last) color it should change color to the first color in the sequence.
First, we create the components for this initial iteration. We are only going to
program one color, but we'll add two color buttons now, as well as a Guess
button and a feedback label.
Next, we open the blocks editor to code the toggling behavior. We'll first
program the behavior for the first color button (ColorButton1). We'll assume
that the button has an initial background color of blue, and that clicking the
first time should change it to Cyan, clicking a second time should change it
to Green, and a third time back to Blue. The user should be able to continue
this sequence forever to choose their color.
When Color1Button is clicked, we check the background color of the button
and compare it to Blue. If it is Blue, we set it to Cyan. If its not Blue, the
outer else-do is executed. This causes a second check, and the background
color is compared to Cyan. If it is Cyan, the color is set to Green. If it is not
Cyan, the inner else-do is executed, and it is set to Blue.
Note that if the first test, Color1Button.BackgroundColor = Blue, is true, the
background color is set to Cyan and the even-handler ends-- the else-do and
the inner test, Color1Button.BackgroundColor = Cyan, is never checked. So
Blue will change to Cyan.
On the next click, the first test will be false, the second test will be true, and
the color will change to Green.
On the third click, the first test will be false, the second will also be false, so
the inner else-do will be executed, changing the color to Blue. On the fourth
click we'll be back to where we started, and the first test will be true.
Summary
Conditional blocks allow for the specification of complex behaviors and
decision-making in an app. This chapter provided some examples of
conditional behavior, including nested conditions that allow for choosing
between multiple alternatives. In the next chapter, we'll examine even more
complex behaviors and continue with the Mastermind sample.
Problems
Complete the following and document on your portfolio:
1. SaveAs your ball animation program into BallGame. Modify the program
so that it reports a win when the player has touched the ball 3 times.
2. Write a callRandomFriend which randomly calls one of your friends when
you run the application. Put at least three numbers into the randomizer and
use an if-else and a nested if-else.
Chapter 6: Lists
This chapter describes how to work with lists of data in an App Inventor
application.
Thus far, in working with variables, we've worked with scalar data, that is,
atomic data like a single number or text entry.
Many applications deal with lists of data. For instance, we might want to
keep track of the list of monsters in a game or a list of friend's phone
numbers. A list is a variable, but instead of representing a single memory
cell, it represents an array of cells:
PhoneNumberList
3219872 4153297878 4592371
App Inventor provides blocks for creating lists, adding elements to lists,
selecting a particular item from a list, and applying operations to an entire
list.
Making a List
A list is created in the blocks editor using a variable block and a make a list
block. Suppose, for instance, that you're writing an app to text a list of
friends with one click. We'd create the phone numbers list in the following
manner:
1. From the Built-In palette, drag a "define variable" block into the program
area and change the name from "variable" to "phoneNumbers".
2. From the Lists palette, drag a "make a list" block in and latch it to the
variable. This tells App Inventor that the variable will store a list of data as
opposed to a single scalar.
3. Since the elements of our list are phone numbers, drag in some text
blocks, enter the desired numbers, and connect them to the "item" slots in
the make a list block. Note that a new "item" slot open up each time you add
a new element to the list.
Your blocks should look something like this:
Note that this definition block can float by itself in the block editor, just like
when you defined numbers or text variables. It does not need to be hooked
into an event handler.
With the blocks above, you've defined a hidden variable named "phone
numbers" which is of type "list" and which has two elements, each of which
is of type text. Now we'll show how you can write event-handling blocks that
use this new list variable.
Selecting an Item
You can access particular items in a list using an index. If a list has five
items, you can access the items with indices 1,2,3,4, and 5. With traditional
programming, you'd write code such as:
phonenumbers[2]
to access the second item in a list. With App Inventor, you use the select
list item block:
With select list item, you plug in the list you want to choose from in the first
slot, and the index you want in the second slot. The blocks above say to
select the second element of the list phoneNumbers. The return value of
select list item for this sample would be "3334444" as that is the second
element of phonenumbers.
Text Random Using a List
You are new ready to create a more elegant version of the text random
friend app. Recall that in that application, you used the random integer
function to get a random number, then used if-else blocks so that if the
random number was 1, the first friend was called, if it was 2, another friend,
and so on.
Using a list, you can eliminate the if-else blocks and use the random integer
as an index into the list. Here are the blocks:
The blocks get a random number between 1 and 2, as the list has only two
items. It then calls select list item with the random number (1 or 2) as the
index. The selected phone number is set as the texting object's phone
number, and the message "miss you" is sent to it. If you run this app
multiple times, it should text the two numbers with equal likelihood.
Using Length of List
One reason the above solution is more elegant is that you don't have to
change the event-handler much in order to make the app work for a
different set of phone numbers. With the old if-else solution, we'd have to
add another if-else block if we wanted a new phone number added. For the
new solution, we can just add an element to the make a list block, e.g.,
There is another detail that must be taken care of, however. When you get
the random integer, the blocks specifically request a number between 1 and
2, so the new third element will never be chosen.
A simple solution is to change the "to" parameter of the random block from
2 to 3. However, this introduces a dependency-- you must always change
that parameter when you change the size of the list. As programmers are
notorious for forgetting things, it's better to avoid such dependencies. You
do not want to introduce bugs when making a change in an app.
The better solution is to make the event-handling code more general.
Instead of putting a fixed upper limit in the random call, you can specify that
the upper limit for the call to random should be the size of the list: if there
are n items in the list, get a random number between 1 and n. Fortunately,
App Inventor provides a list operation to help: length of list. Here is the
modified program:
The change is near the right: the "to" parameter to random integer is no
longer a fixed number. Instead, it is the result of the function "length of list".
This solution is maintainable-- the programmer can make the app work for
more or less numbers by simply modifying the entries into "make a list". It
will also work for apps that have dynamic lists, i.e., apps in which the user
(not the programmer) is allowed to add or remove numbers from the list.
This is important given that, generally speaking, you want to write apps for
others, not just for yourself!
Toggling through colors using a list.
In the previous chapter on conditional statements, you programmed a
button that sequenced through color choices when it was clicked. For the
purposes of comparison, let's write it using a list of colors instead of a
nested if-else. The advantage with this alternative solution is that our code
will work even if we change the colors or number of colors that should
appear.
The first step is to define a list variable for the colors:
Along with the colors list, you need to keep track of the current color. For
this, you'll define another variable to use as an index. An index is a position
in a list. Since you'll start with the first color, initialize it to 1:
Now you're ready to code the click event for ChooseColorButton. On the
click, first add one to the currentColor. The call select list item using the
colorIndex as the index:
As is, the app will begin with a blue button background. The first time the
button is clicked, colorIndex will change to 2, and the button background will
be changed to Cyan. The next click will change colorIndex to 3 and the color
to Green. What happens on the next click?
If you thought, "error", you are correct. colorIndex will become 4 and then
the app will try to select the 4th item in the list, but the list only has 3 items.
To fix this, use an if-then block to handle the case when the last color in the
list is reached:
The event-handler here and the corresponding one you created in the
Conditionals chapter both cause the same behavior, just in different ways.
The first uses a nested if-else to choose the next color, while the latter uses
a list and an index variable to choose the next color.
The advantage of the latter method is that the list of entries can be modified
and the app will still work. As most apps work with dynamically changing
data, this is a very important difference.
Iterating Through a List: For Each
Now suppose we wanted another button for the app and that when the user
clicked it, the text would be sent to all the numbers in the list, not just a
random one.
A brute force method for such an event-handler would look like:
With this method, the blocks to set the phone number and send the
message are copied 3 times. For three numbers, this isn't too awful, but
what if we wanted to text 100 or 1000 numbers? The program would be
quite large. Furthermore, the programmer would have to add three blocks in
order to add a new phone number to the one's called.
Fortunately, we can use our "phonenumbers" list and a special block "for
each" that allows us to apply some operations to all elements of a list. Here
is the more elegant solution:
This code says that "for each phone number 'pnum' in the list
'phonenumbers', set the text object's phone number to pnum and send out
the text message".
The foreach block can be found in the control drawer, the same place where
the if-else is. When you drag a foreach block into the program area, you
must specify the list that will be processed as the "in list" parameter at the
bottom of the for-each block. In this case, the list is the global
"phonenumbers".
At the top of the foreach block, you can also provide a name for the
placeholder variable. Often, you'll name it "item", as this variable represents
an item in the list. In this case, we named it "pnum" as it represents one of
the phone numbers in the list.
The foreach block is one method of iterating in a program. To iterate means
to repeat some operations over and over. The blocks that are slotted into
the foreach block's "belly" will be repeated for each item in the list. In this
sample, the blocks that are repeated are:
We say that those blocks are subordinate to or within the foreach block. We
say that the program "loops" back up when it reaches the bottom block
within the for-each.
The app executes in the following manner: when the TextAllButton is clicked
and the event-handler called, the first operation executed is the "set
Texting1.Message to" block, which sets the message to "miss you". This
block is only executed once.
The for-each block is then entered. The variable pnum is set to the first
number in the list phonenumbers ("3594787"), and the blocks within the
foreach are executed for the first time. The Texting1 object's PhoneNumber
property is set to pnum ("3594787"), and the message is sent.
Because we are within a foreach, the app "loops" back up to the top of the
foreach and puts the next item in the list ("3779199") into pnum. The two
operations within the foreach are repeated, so the text is sent to "3779199".
The app then loops back up again and sets pnum to the last item in the list
("8143549"). The operations are repeated a third time causing the third text
to be sent.
This time, when the app loops back up, it realized there are no more items
to process. The app "pops out of the loop" and continues on after the
foreach block. In this case there are no blocks below it, so the event-handler
ends.
This solution is maintainable because it will work even if new numbers are
added to the phonenumber list-- the foreach will process however many
items are in the list.
Getting Started
QuizMe is a trivia game about baseball, but you can
use it as a template to build quizzes on any topic.
With QuizMe:
The user steps through a series of questions,
clicking a Next button to proceed to the next
question.
The user enters an answer for each question
and the app reports whether each answer is
correct or not.
For this tutorial, you'll create an app in which the
questions are always the same unless you, the
programmer, changes them. Later, you can create
MakeAQuiz, an app that lets users create and
modify the quiz questions. This tutorial assumes you
are familiar with the basics of App Inventor -- using
the Component Designer to build a user interface,
and using the Blocks Editor to specify event-
handlers-- both of which are explained in the
HelloPurr, PaintPot, and WhackAMole tutorials.
Connect to the App Inventor web site and start a
new project. Name it QuizMe, and also set the
screen's Title to QuizMe. Open the Blocks Editor and
connect to the phone.
Also download these pictures of baseball players and
save them on your computer: larsenberra.jpg, dallasbraden.jpg,
cyyoung.jpg, nolanryan.jpg.
Example: Quiz App Version 1
Specification: The quiz app will display a single question at a time. The user
enters an answer and clicks the "submit answer" button. The app responds
by either displaying "correct" in the reply label, or displaying "incorrect: the
answer is x". The user clicks on a next button to see the next question.
UI Design: We'll begin with a simple user interface: a question label where
the question will be displayed, and AnswerBox where the user will answer, a
SubmitButton that the user clicks when answer is in, a ResponseLabel that
will display "correct" or "incorrect", and a NextQuestion button that the user
clicks to get to the next question.
Iterative Development Strategy: We'll first develop a version that just lists a
question and responds to the next button by displaying the next question.
For now, we'll ignore the user's answers.
Iteration 1: Questions and the Next Button.
In the blocks editor, our first task is to create a list of the questions. We'll
drag in a define variable block and a make a list block, and populate the list
with some questions:
Next, we want to get the first question in the list to display when the app
begins. We'll use an Initialize event block of a component, in this case the
QuestionLabel, to define this behavior. Remember that Initialize is called on
each component as the app is starting up, so whatever we do here will
appear when the user first sees the app. Here are the blocks:
We use the select list item block to grab the first item from the questions list
(note that the list parameter is set to "questions" and the index to 1). The
result, in this case "who wrote Remix?" will be displayed in the
QuestionLabel.
Of course, we could have put the text "who wrote Remix?" directly in the
QuestionLabel.Text. But we want to write the behaviors so that they will
work on any list, and will work even if the list is rearranged. The more
general "select the first item of the list and put it in the QuestionLabel" code
allows for this.
Our next task is to program the behavior of the next button. To do this, we
need to remember what question we are on at all times. To remember
something, we just define a new variable. In this case, we need to
remember the question number, i.e., the index into the list "questions":
Note that this variable definition, like all of them, should be placed outside
the confines of any event-handler, just floating by itself in the program area.
Now that we have the questionNum variable, we can program the
NextButton event handler. What we want to do is to increment the
questionNum variable, e.g., change it from 1 to 2 or from 2 to 3, and then
display the next question. Here are the blocks:
This is some sophisticated code. The first operation sets the questionNum
variable to itself plus 1. This is typically quite confusing for beginning
programmers. The way to conceptualize it is to first realize that the variable
questionNum represents a memory cell with some number in it:
questionNum
1
The user of the program can't see it, but that memory cell is in the phone's
memory because of the questionNum variable definition we performed
earlier.
The second thing to realize is that you have to read sequences of blocks
right-to-left. For the blocks:
the + operation is executed first. It says to take the value in questionNum
and add 1 to it. When the program first starts, the value of questionNum is
1, so by adding 1 we'll get 2 as the result of the + operation.
The result of the plus, 2, is then slotted into the set global questionNum to
block, i.e., 2 is put into questionNum. This causes the hidden memory cell to
no longer have a 1, but instead have a 2:
questionNum
2
Sometimes when we're tracing a program on paper to understand how it
works, we'll cross out the old value and place the new one after it:
questionNum
1
2
and we'll leave off the box around the memory cell. This shows the history of
execution, which can be helpful. But always remember that a memory cell
holds one thing only, and the 1 is gone as soon as we (re-) set the variable
questionNum.
So the first operation in the event-handler changes the hidden variable
questionNum to one bigger. The second operation:
then uses this modified variable questionNum as the index into the list
questions. Just like we might say, "get the 2nd item from a list", or "get the
third item from a list", these blocks read as "get the 'questionNumth' item
from the list. The app, when executing the select list item operation, must
first evaluate the index parameter, which is the non-fixed value
"questionNum". There could be anything in questionNum, but whatever that
number is will be used for the index. If questionNum has 2 in it, we'll get the
second item from questions ("who wrote The Big Switch") and put that into
QuestionLabel.
The event-handler we have so far would work fine until the user got to the
third (last) question. At that point, when the user clicked next, questionNum
would have a value of three. We would then increment questionNum,
changing it to four, and the select item call would ask for the 4th item in a
three item list. This would cause the app to Force Quit, or as programmer
say, "bomb out".
So we need to modify the blocks so that, when the NextButton is clicked we
do something differently if we are on the last element of the list. Here's a
solution:
The if-else block comes to the rescue: if questionNum is equal to the length
of the questions list, we reset questionNum back to 1. So if questionNum is
3 and there are three things in the list questions, the test will be true and
the app will execute the then-do branch.
If questionNum is 1,2, or in general any number less than the length of the
list, the else-do branch is executed and we increment the questionNum.
Other solutions are of course possible: we could leave the questionNum at
its max once its reached or we could gray out (enable=false) the next button
once questionNum does reach its limit. The important thing for a
programmer is to understand how to convert the specs of an app into blocks
like the one in this example.
Iteration 2: Processing Answers
This is left as an exercise (see problem 2)
Summary
Lists allow us to give a name to related items. Then with list operations we
can index into the list to grab particular items and even apply some
operations to each element of the list. This ability to group can reduce the
size of a program and make it more maintainable.
Problems
1. Sum of a list app: Create a list "numbers" with at least three integers,
then use a foreach block to compute the sum of the numbers in the list. For
instance, if the list had the numbers 3,5, and 7, your app should display 15.
2. Quiz app: Extend the iteration 1 solution given in the text to create a
complete quiz app. You'll need another list, answers, and you'll need another
event-handler to handle the AnswerButton.Click event.
Solutions:
Add a List
3. Complete a quiz application:
The first question should be displayed on startup.
When the user clicks next, the next question is displayed.
When the user clicks next on the last question, the first question is
displayed again.
When the user enters an answer and clicks "Answer", the app checks
the answer and reports either "correct" or "incorrect, the answer is..."
showing the correct answer.
You should have two lists, one for questions and one for answers, and
use an if-statement to check if the answer is correct.
Chapter 8: Iteration
The previous chapter discussed lists and methods for iterating through a list,
that is, applying some operations repeatedly to items in a list. This chapter
continues the discussion of iteration and introduces the while-do block. In
the chapter, you'll learn how to write mathematical apps such as one to sum
up the first n numbers and another to compute factorial(n).
Computers are great at doing the same task over and over. They never get
tired. As the chapter 4 discussion of the for-each block showed, the blocks
within an event-handler need not be linear "recipe" like programs, but can
contain repeat loops that execute some operations over and over.
In App Inventor, there are two blocks for specifying repeatable code: the
for-each and the while-do. The text everyone in a list app in Chapter 4 used
a for-each block to text all the phone numbers in a list.
The while-do is a bit more complicated to use, but it is more general than
the for-each: whereas the for-each is specifically for repeating operations on
each item of a list, a while-do can repeat any operations. Furthermore,
whereas the for-each always repeats once for each item in the list, with the
while-do the programmer can specify that the operations repeat while any
arbitrary condition is true (the converse way to put it is that the program
can repeat until any arbitrary condition becomes false.
With a while-do, the app checks a condition, and if its true, executes some
operations (B in the diagram). After completing B, the app loops back up
and rechecks the condition again. If its still true, B is repeated. If it is false,
the app "pops out of the loop" and continues with C.
Computing the Sum of the First Three Numbers
What is the sum of the first 3 numbers? What is the sum of the first 5
numbers? The first N numbers? How did your brain compute it?
The hard thing about programming is usually not the problem we are
solving: most of us can add up 1+2+3=6. The difficult part of it is breaking
your thought process down so that you can instruct a computer to do the
same thing.
When you add up the first so many numbers, your brain probably uses two
memory cells-- one is a counter for the new number you're adding, and one
for a "running sum". So you begin with 1 as the couner and 1 as the sum.
Then you get the next counter 2 and add it to your sum, giving you 1+2=3
as the sum. Then you get the next counter 3 and add it to the running sum,
which is 3. This gives you a new sum of 6. Then you get 4 and add it to the
running sum, giving a new sum of 10. And so on.
If we were to trace these memory cells, we'd get:
counter sum
1 1
2 3
3 6
4 10
This is how your brain works, but how do you get an app to do the same
thing? This is where a while-do comes into play.
Let's start by writing an app that sums the first 5 numbers. Later, we'll
generalize it to sum up the first n numbers, where n is some number input
by the user. Here's pseudocode for what we want:
set counter to 1
set sum to 0
repeat while counter is less than or equal to 6:
add the counter to the running sum
increment counter
Now let's convert this pseudocode into an App Inventor app. First, we need
to define two variables, which we'll call "counter" and "sum":
Next, we drag in a while-do block from the Control drawer of the built-in
palette:
Note the the while-do has a test just like with the if and ifelse blocks. With
both, the app performs the blocks inside if the test is true. The difference is
that with the while-do, the app loops back up and checks the test again each
time after executing the inside blocks. A while-do does something 0 or more
times. An if does it 0 or 1 times.
In this case, we want to add up the first five numbers, so we want to repeat
while the counter is less than 6. We'll add one to the counter each time so
that at some point it will become 6 and the app will "pop-out of the loop".
Here's how we fill in the while-do block:
When we reach the while test the first time, the value of counter is 1. Since
1 is less than 6, the app will execute the operations within the while-do, in
this case the modification (set) of the sum and the modification (set) of the
counter. So sum becomes 0 +1 = 1 and counter becomes 1+1 = 2.
counter sum
2 1
After the counter is modified, we reach the bottom of the while-do (note that
the blocks to modify TotalLabel.Text are below the while-do loop and will not
be repeated). When the bottom is reached, the app loops back up and re-
tests the while test (counter<6). Now counter is 2 which is still less than 6.
So we repeat the blocks within the while again. This time sum becomes
2+1=3, and counter becomes 2+1=3:
counter sum
3 3
We loop back up and test, and counter is still less than 6. After we repeat
twice more, we have:
counter sum
5 10
When we check the test, counter (5) is less than 6, so we go in the while
again. sum is changed to 15 and counter to 6:
counter sum
6 15
Now when we loop back up and check the test, it is false. When the while
test is false, we "pop out of the loop" meaning we don't again repeat the
operations within it. Instead, the app jumps to the blocks below the while
loop, in this case the blocks to display the sum in TotalLabel.Text. The
correct value 15 is displayed and the event-handler is complete.
Computing the Sum of the first N Numbers
Changing the app so that it can add up numbers up to any number n the
user enters is relatively straight forward. We just introduce another variable,
n, and set it to the value of the textbox in the user interface above the
while-loop. We then modify the test so that it no longer tests that the
counter is less than 5, but less than n+1:
Now if the user enters a 5 in the NText text box, the variable N will be set to
5 and the while-do will repeat 5 times. And in fact, the app will display 15 in
the TotalLabel.Text box, just as with our previous solution.
If the user closed the app and re-started it, then typed in a 3, the app would
correctly display 6 as the sum.
A Bug in the Program
Now let's consider the case when the user enters a number and clicks the
SumItButton, then enters a new number and clicks it again, without
restarting the app. Specifically, assume the user first enters a three and
clicks, then enters a 2. After correctly answering 6 the first time, the app
would report that the sum of numbers from 1 to 2 is also 6! Watson, we
have a bug! Can you step through the app to see what the problem is?
The problem lies in the fact that counter and sum are only initialized when
the app starts, based on the variable definitions. In our scenario, after the
app correctly computes the sum of 1 to 3 as 6, the values of the variables
are:
counter sum
4 6
When the user then enters a 2 in NText and clicks the SumItButton again,
those values are still in counter and sum-- they are not re-initialized, even
though we really want to start over.
The solution is to initialize the variables within the event-handler so that
each time the SumItButton is clicked, the computation begins anew. Here is
the fixed solution:
Because the initializations of counter and sum are within the event-handler,
the sum will be computed correctly every time.
Problems
1. Write a factorial(n) application.
2. Write the text all numbers in a list app using a while-do instead of a for.
Chapter 9: Web Services, APIs
and Mashing Data
This chapter introduces web services, APIs, RSS, and mashups, then steps
through the development of an Android app that communicates with the
Twitter API.
To computer users, the web is a bunch of sites that can be visited with a
browser. Programmers see things differently-- to them the web is also a
huge database of information which can be collected and processed
(mashed) to create new and interesting apps.
Consider, for instance, the custom bookstore sites that sell books using
Amazon's database of information along with their facilities for on-line
transactions.
Such custom bookstores are possible because Amazon, like many sites,
provides two levels of access to information: a human interface and an
application programmer interface (API):
Most of us have used the human interface by typing in amazon.com into a
browser. But let's say you were a basketball enthusiast and you wanted to
setup a site for selling books about basketball. You could write a web app-- a
computer program-- that made calls to Amazon to perform searches and get
information about particular books. Your program could organize the data,
combine it with other data (e.g., pictures of NBA stars), and display that
information to visitors of your "basketballBooks.com" site.
Your program would communicate with Amazon, but instead of using
amazon.com, as a person would do, your program would communicate with
their API interface. API stands for application programmer interface and an
application programmer is one who writes apps-- the basketball store
creator, in this case. An API provides for computer-computer
communication, one program talking to another, as opposed to a web app,
which provides for human-computer interaction.
Technically, an API is the specification that describes how your program
should talk to the web service at some server's site-- the type of requests it
expects, and the format of the data that will be returned to your program.
Often, the data returned is some form of extensible markup language (XML),
though there are also JSON APIs. The API tells the client programmer how to
communicate with the web service.
Whereas HTML is the language used when a server sends information to a
browser for human consumption, XML is generally used when a server sends
information to a program on another server. Both HTML and XML include
data within them (e.g., book information), but HTML also has presentation
information-- specifications for how the information should be displayed--
while XML does not.
Here's an example of a search at amazon.com for Books about Baseball. The
search returns a page that looks like this:
The HTML behind this page is extremely complex and includes both the data
you see and code for styling that data (e.g., code specifying that the book
images should be aligned). Here's an abridged version of the HTML code:
<html>
<head>
<style type="text/css"><!--
BODY { font-family: verdana,arial,helvetica,sans-serif; font-size: small;
background-color: #FFFFFF; color: #000000; margin-top: 0px; }
...
<div class="productImage"><a href="http://www.amazon.com/
Baseball-Prospectus-2010/dp/0470558407/
ref=sr_1_1?ie=UTF8&s=books&qid=1264011867&sr=1-1"> <img
src="http://ecx.images-amazon.com/images/I/
51kRbJCrDoL._SL160_AA115_.jpg" class="" border="0" alt="Product
Details" width="115" height="115"/> </a></div>
<div class="productData">
<div class="productTitle"><a href="http://www.amazon.com/Baseball-
Prospectus-2010/dp/0470558407/
ref=sr_1_1?ie=UTF8&s=books&qid=1264011867&sr=1-1"> Baseball
Prospectus 2010</a> <span class="ptBrand">by Baseball
Prospectus</span><span class="binding"> (<span
class="format">Paperback</span> - Feb 22, 2010)</span></div>
The important thing to understand is that browsers understand HTML code
and use all the added styling information to render a page. However, it is
clear to see that extracting just the data, e.g., the title of the books, is not
so easy. A computer program reading this data in order to just grab the
titles would have to know within what HTML tags that data resides. The code
to parse this HTML-- to extract the data- would be non-trivial. Furthermore,
if the HTML styling changed, the program code to parse it would no longer
work!
This is the reason many web sites provide a non-HTML API web service that
returns data in some well-documented XML language. The client code can
call the service with a URL, as in the following example:
http://ecs.amazonaws.com/onca/
xml?AWSAccessKeyId=1x1x1x1x1x1x1x1
1
&Keywords=baseball&Operation=ItemSearch&SearchIndex=Books&Service=AWSECommerceService&Timestamp=2010-01-20T18%3A10%3A14.000Z&Version=2009-03-31&Signature=LAu8sU4nKvh0R6AbEQuFfAne27mCFDqVYiqUudGpkcc%3D
This URL is in the same format of the URLs that humans use to navigate the
human web. But instead of returning HTML, it returns XML in Amazon's
(fairly) well documented API. You can see the response I got from this
request here:
http://www.cs.usfca.edu/~wolber/amazonResponse.xml. Here is an
abridged version:
<ItemSearchResponse>
<Items>
<Item>
<ASIN>0470558407</ASIN>
<ItemAttributes>
<Author>Baseball Prospectus</Author>
<Manufacturer>Wiley</Manufacturer>
1. The 1x1x1x1x1x1x must be replaced with an Amazon access key for this
URL to work. Anyone may sign up for such a key.
<ProductGroup>Book</ProductGroup>
<Title>Baseball Prospectus 2010</Title>
</ItemAttributes>
</Item>
<Item>
<ASIN>1600783554</ASIN>
<ItemAttributes>
<Author>Ron Shandler</Author>
<Manufacturer>Triumph Books</Manufacturer>
<ProductGroup>Book</ProductGroup>

<Title>
2010 Baseball Forecaster (Ron Shandler's Baseball
Forecaster)
</Title>
</ItemAttributes>
<Items>
<ItemSearchResponse>
The response has a list of items, and each item has a set of tagged
attributes including title, ISBN, etc. The XML is much easier to parse
compared to HTML and the expectation is that it won't change without the
source site giving ample warning (and they don't need to change it for
stylistic reasons, as with the HTML interface).
So a mashup program can call the amazon API, and perhaps call other APIs
such as the Google Books API or a library's API. After the program parses
the XML, the various data is all stored in the program's memory. It can then
process it, organize it, and eventually display it in any manner it would like.
If its goal is to sell books, Amazon provides methods for allowing custom
book sites to earn money on click-throughs.
Here's how product advertising works, from Amazon web site:
1
Your application uses the Product Advertising API to supply item
descriptions and images, and customer and seller reviews, which you
present to your customers.
2Customers shop on your web site.
3
When the customer is ready to purchase the items in their e-commerce
shopping cart, your application sends an HTML form to Product Advertising
API and Amazon completes the purchase by getting purchase information,
such as payment method and shipping address, and then Amazon fulfills
the order by shipping the items.
http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/
Some APIs are simple than Amazon's. For instance, Yahoo provides financial
information with a URL that returns simple comma separated data. For
instance, the URL:
http://download.finance.yahoo.com/d/
quotes.csv?f=sl1d1t1c1ohgv&e=.csv&s=IBM
returns the text:
"IBM",75.97,"11/19/
2008","4:01pm",-4.11,79.93,81.00,75.73,12606807
The API specification is simply this: the commas separate these nine pieces
of information:
Ticker symbol
Last price (after a 20-minute delay)
Date of that price
Time of that price
Change since the day's opening
Opening price
Day's high price
Day's low price
Trade volume
Mashups
The term mashup perhaps originated in the music field, with Eminem's
album The Slim Shady LP combining samples from various other songs and
artists.
Today, numerous sites like ccmixter help artists mashup samples and create
new art. Combining previously created art is controversial of course, due to
copyright issues. For a great introduction to the general concept of mashups
and the societal implications, see Lawrence Lessig's book Remix (you can
find it for free on-line at http://www.bloomsburyacademic.com/remix.htm)
Just as music can be remixed, so can web programs and information. To a
programmer, a mashup is a program that takes data from multiple sources
(APIs) and combines it in interesting ways. Custom bookshops that combine
data from multiple APIs would be considered mashups, but there are many,
many more that use APIs from all walks of life. The site
http://www.programmableweb.com/ provides a dynamic list of interesting
APIs and mashups. Perhaps the most popular example, and one of the first,
is housingmaps.com which combines data from craigslist.com and Google's
maps API. Here's a snapshot of it showing craigslist listings plotted onto a
map of San Francisco:
Tweeting Big Stock Swings To Twitter
Another interesting example of a mashup was provided by Bob DuCharme at
http://www.devx.com/webdev/Article/40511/0/page/1. Bob combined
Yahoo's stock information with the Twitter API to create a mashup that
twitters him when a particular stock has a swing of 50 or more points. This
diagram illustrates how it works:
In this mashup, DuCharme's server program requests data from Yahoo
Finance, which returns it in comma-separated value format. His program
then processes it by checking it against its previous readings. If there is
more than a 50 point difference, it uses the Twitter API to change the status
on his twitter page. Bob and other humans can then check his twitter page
for updates.
RSS
RSS stands for Really Simple Syndication. RSS is a specific XML language
that is used by most blogs and in general any service that just needs to send
out a simple list of items in an XML format.
Because RSS is so common, there are many clients and code libraries for
processing RSS data, so you can help people access your data by putting it
in this format. Note, however, that RSS is a fixed protocol-- if you have
custom data you either have to fit it into RSS fields or define your own XML
schema. For instance, the XML returned by Amazon, shown above, is not in
RSS because Amazon provides pricing and other information that doesn't fit
into the RSS protocol.
Creating Mashups
Mashups are generally created in high-level programming languages such as
Python, Java, or Perl. Most information sources generally provide client
library code in these popular languages that makes data access easy. In
general, however, creating mashups requires sophisticated programming
knowledge.
There have been some advancement in tools for "end-user" creation of
mashups. The term end-user in this context means someone who doesn't
know how to program in a traditional textual language such as Python or
Java (which includes most of the world).
Yahoo Pipes is one such end-user tool. With it, you can link various web
services and RSS data sources together to create mashups. Here's an
example of a pipe that mashes NY City apartment information with user
input:
This pipe allows the user to enter a NYC neighborhood, a keyword, and a
minimum distance. In the sample shown, the user is looking for apartments
near a park in Manhattan.
The pipe was created without any programming, at least of the traditional
textual kind. Here is what development looks like:
The developer just drags in functional nodes for getting user input,
extracting data from sources, fitering, and displaying data. In the sample,
for instance, the top node prompts the user for the neighborhood (the
"where"), then funnels that information to a URL builder that creates a call
to the API http://newyork.backpage.com/online/exports/Rss.xml. The
results are then filtered by location and another input by the user, "what"
(by default, the "what" is "park", but the user can enter any place for which
they'd like to find an apartment that is near).
Sergey Brin Quote, stats about more computer->computer communication
than human-communication
Twitter API
Twitter has an API that return data in RSS format. For instance, one of the
API commands returns the public timeline (the newest twits from the world).
if you enter:
http://twitter.com/statuses/public_timeline.rss
in a browser, the browser will render something like:
This is just because most browsers will render RSS in a format that's nice for
viewing content. Really, the RSS sent to the browser looks like:
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"
xmlns:georss="http://www.georss.org/georss">
<channel>
<title>Twitter public timeline</title>
<link>http://twitter.com/public_timeline</link>
<atom:link type="application/rss+xml" href="http://twitter.com/
statuses/public_timeline.rss" rel="self"/>
<description>Twitter updates from everyone!</description>
<language>en-us</language>
<ttl>40</ttl>
<item>
<title>Juliana_Madeira: &quot;&#201; triste pensar que a natureza
fala e que o g&#234;nero humano n&#227;o a ouve.&quot; Victor
Hugo</title>
<description>Juliana_Madeira: &quot;&#201; triste pensar que a
natureza fala e que o g&#234;nero humano n&#227;o a ouve.&quot;
Victor Hugo</description>
<pubDate>Wed, 20 Jan 2010 20:10:23 +0000</pubDate>
<guid>http://twitter.com/Juliana_Madeira/statuses/
7998009238</guid>
<link>http://twitter.com/Juliana_Madeira/statuses/7998009238</link>
</item>
and the browser has processed it to render it.
This URL returns a particular person's friend timeline:
http://twitter.com/statuses/friends_timeline.xml
If you type this command in a browser, it will prompt for a valid twitter
username and password. You can also enter a URL of the form:
http://username:password@twitter.com/statuses/friends_timeline.xml
replacing "username" and "password" with your own authentication.
Putting REST URLs directly in a browser gives you an idea of how an API
works, but generally these requests will come not from a person, but from a
program. Your program will make an HTTP request, generally using high-
level "client" library code for the particular language you are using, and
hiding the URL details. The library code also takes care of parsing the XML
returned from the service, providing your client with an easy-to-process list
of data.
An App Inventor Twitter Client for Android
An Android programmer, using the Java SDK, could communicate with any
API. App Inventor, however, does not yet provide blocks for calling an
arbitrary API. It does, however, provide blocks for communicating with the
Twitter API.
The blocks consist of request blocks and request-received blocks. Request
blocks are used to send requests to the Twitter API: a request to login, a
request to get the friends_timeline, etc. Typically these requests will be
made from within some event-handler (e.g., when the user clicks a button
labeled "view friends timeline".
Requests are not processed immediately-- when you request a timeline, for
instance, the timeline is not provided as the return value of the block.
Instead, request and reply are asynchronous. You send the request with one
block, then specify an event-handler that will be triggered when the app
receives the request from Twitter.
This separation of request and reply is mandated by the Android system, as
Android wants apps to always be ready to respond to external events,
instead of waiting for some external request to complete.
Here's some program blocks that make use of two request-->handle event
sequences:
In these blocks, we first make a Login request to Twitter. While this
interaction is occurring, the program could handle other user or external
events. When Twitter logs the user in, it sends notification back to the phone
app, and the IsLoggedIn event occurs, triggering the corresponding event-
handler. The programer has set things up so that, in the handler for
"IsLoggedIn", it issues another request with RequestFriendTimeline block.
Once again the app is free to handle other events while Twitter is doing its
job. When Twitter returns the timeline, the FriendTimelineReceived event
occurs, and the program processes it by displaying the information.
Problems
0. Create a mashup using Yahoo Pipes
1. If you don't have a Twitter account, register and get one. If you have one
already, you may want to register with another account for the tutorials we'll
be doing.
2. Add at least one status message on the account, and follow at least one
person and get at least one person to follow you.
3. On your phone, download an Android Twitter client and post a status
message from it. What features does the Twitter Client you chose provide?
Provide a screenshot of your Twitter Client and a description of its features
4. Now create a Twitter Client of your own using App Inventor. You can do
so using the tutorial at: http://sites.google.com/site/appinventorhelp/
tutorials/twitterdemo
5. Write an Android application that combines texting and twitting. For
instance, the app might text one of your friends when you've added a new
status message on Twitter. You don't have to do exactly this-- be creative!
Chapter 10: Persistent Data
Most interesting apps keep track of data over time, usually in some type of
database. App Inventor provides two components, TinyDB and TinyWebDB,
which allow your app to put things in a database and retrieve them later.
This app discusses these components.
** Note: This text was written before the TinyDB component was added to
App Inventor. TinyDB lets you store/retrieve data to persistent storage that
lives directly on the phone. TinyWebDB stores/retrieves to a web database.
TinyDB is simpler-- you just StoreValue tag-value pairs, and call GetValue to
get them back. With TinyWebDB storing is the same, but to retrieve data
you request with GetValue and then let the GotValue event handle things
when the data arrives. But since the data lives off the particular phone,
TinyWebDB can be used for sharing amongst phones/apps (e.g., multi-
player games).
** End Note **
The apps we've looked at so far have used only transient data. Transient
data is short-term: it is initialized when an app begins, and it "dies" when
the app ends. It exists only within a particular phone and a particular
instance of an app.
Consider, for instance, the quiz app discussed previously. The quiz questions
(and answers) are stored in a list. The list of questions is always the same
for every run of the app. A programmer can change the questions in App
Inventor, thereby creating a new version of the app, but the end-user has
no way to modify the questions or add new questions.
Now suppose you wanted a quiz app that allows one end-user (the teacher)
to change or add new questions. You might envision a parent creating
various quizzes for their child on a long car-trip, or a school teacher setting
up quizzes for students.
Given what we've learned so far, you could write an app that allows the list
of questions to be changed. The user would enter new questions and
answers in text boxes, click Submit, and the event-handler would add new
entries to the list. Such a scheme would work reasonably in the car-trip
scenario-- with the app continually running, the parent (quiz creator) and
child (quiz taker) could pass the phone back and forth.
The scheme is limited, however, because the lists in App Inventor are
transient data: when the app is closed, changes to lists are not recorded.
Any questions entered by the user during a single "run" of the app are lost
when the app is closed, and the next time the app is opened, it will show
only the questions that are fixed part of the list blocks. Furthermore, the
questions entered live only on the particular phone on which they are
entered. So a teacher couldn't write a quiz for her students and allow them
to take the quiz on their own phones.
What our app really needs is access to a database that lives on the web
some place, and that can be accessed by multiple phones.
Persistent data is information stored in a database or a file. It is persistent
in that even when the user closes the app, the data lives on. An example of
persistent data is your profile information on Facebook. When you submit
data to Facebook, the data you submit is stored in a database on the
website's servers. This data is persistent since it will be there the next time
you visit the site or run a Facebook app.
With App Inventor, list variables are not persistent, so the app cannot just
put teacher-submitted questions in a list. Instead, the app must store
submitted the questions in a database. This way, when a student decides to
take a test, even from a different phone, it can access the updated questions
from the datbase. The next section demonstrates how to store to and
retrieve from a database in the App Inventor world.
TinyWebDB
App Inventor provides a component, tinywebdb, which allows for apps to
store and retrieve data from a database. The component can store data on
any web service that follows a particular protocol.
The TinyWebDB component is found in the Not ready for prime time drawer
of the designer. When you drag a TinyWebDB component into your app, it is
placed in the 'non-visual component' area.
The component has one key property: the ServiceURL. By default, the
ServiceURL property is set to http://appinvtinywebdb.appspot.com, which is
a test service set-up by the Google App Inventor team. This test service is
shared by many and has a limit of 100 entries, but it can be used to try
things out.
For production apps, you'll want to set-up a service that you don't share with
other apps. For this sample, we'll use a service set up at the University of
San Francisco: http://usfwebservice.appspot.com:
The TinyWeb DB component is straight-forward to use: you call StoreValue
to store data with a tag and value. You request previously stored data by
calling GetValue and providing a tag. When your phone receives the data
from a request, a GotValue event is triggered.
To illustrate how things work, we'll begin with simplified version of the quiz
app, one with only one question and answer. We'll consider only a "teacher"
app that allows a teacher to view and modify the stored question and
answer. As an exercise, we'll consider a second app that allows a student, on
the same phone or another, to take the single question quiz.
With the teacher app, suppose there are two text boxes, Question Text and
AnswerText, in which the teacher enters the question and answer. When the
teacher clicks submit, the text that has been input in those boxes is stored
to the database using TinyWebDB.
Here are the blocks for the SubmitButton.Click event-handler:
The blocks just call the TinyWebDB.StoreValue function twice, once to store
the question, with a tag of "QuizQuestion", and one to store the answer,
with a tag of "QuizAnswer". The value of each is the text that the user has
input into the respective textbox.
This code doesn't change anything in the phone's display. Instead, its
purpose is to modify the database. If the user enters "Who is the President
of the U.S.?" in the QuestionText box, and "Obama" in the AnswerText box,
the following entries would be put in the database:
tag value
QuizQuestion Who is the President?
QuizAnswer Obama
If the user closes the app, this data remains stored in the database.
The next time the user (teacher) opens the app, the app should display what
was entered previously. To facilitate this, the app calls the GetValue function
in the TinyWebDB.Initialize event:
TinyWebDB.GetValue requests data with a given tag. Here, we make two
requests, one for the question and one for the answer, using the same tags
we used to store the data above.
The GetValue function doesn't get a result directly; it just makes a request
to the TinyWebDB web service. After making the requests, the app is free to
handle other events while the web service is sending the requested data.
When the the requested data arrives at the phone, a GotValue event is
triggered. It in this event-handler that the app can do something with the
data it requested. Here are the blocks for the GotValue event:
Both the requests the app made in the Initialize event will trigger GotValue
events, so the Got-Value event-handler will be invoked twice. Because of
this, the handler must first ask which data is being received. Each entry
received contains both the tag and the value, so the handler can ask if the
tag returned was "QuizQuestion". If it is, the app takes the value ("Who is
the President of the U.S.?") and places it in the QuestionText.Text.
If the tag is not "QuizQuestion", it must be "QuizAnswer", so in the "else-do"
blocks the app places the value ("Obama") in the AnswerText.
A Quiz with Multiple Questions
Now let's extend the simple quiz application so that there are multiple
question and answer pairs. We'll still focus on the teacher app for creating
quizzes.
Here's a simple "teacher" interface for entering test questions:
Previously entered question-answer pairs will appear below the text "Existing
QAs".
The application will put entries into tinyweb db in the following the form:
tag value
WolbQuiz:1 What is the capital of California:Sacramento
WolbQuiz:2 What is the capital of Washington: Olympia
Each tag consists of a keyword to identify this particular application,
"WolbQuiz", along with a number that uniquely identifies the question. Later
in this lesson, we'll discuss how to build the tags using text and join.
The tags must be designed so that they can be reproduced to access the
data in the value field. They shouldn't contain dynamic data-- data that the
user enters-- because our app doesn't know what that data will be. For
instance, you wouldn't want the question to be a tag because the questions
themselves are dynamic data.
The value of each entry in our scheme has both the question and answer,
with a colon separating.
The sample app in this lesson is active. You can check out the actual quiz
questions by visiting the web interface to the tinywebdb service at:
http://usfwebservice.appspot.com. When you get to the page, click on
getvalue and enter a tag such as "WolbQuiz:1".
Programming the Behavior of the "Teacher" Application
Following are the blocks for the teacher app:
On start-up, the app needs to load in the questions from the database so
that the teacher can see the current quiz. The strategy is to request the first
question-answer pair using "WolbQuiz:1". If it returns with a value, the app
requests the second question, and so on, until a request is made that
doesn't not return us a valid value. For example, if there were four questions
stored in the web service, our fifth request ("WolbQuiz:5") will return an
empty value since there is only tags up to "WolbQuiz:4". At that point, the
app knows all questions have been loaded.
The TinyWebDB.Initialize event triggers this process by calling GetValue with
the first key, "WolbQuiz:1". "WolbQuiz:1" is built using a join operation: we
join the text "WolbQuiz:" with the variable qnum.
When the app begins, the variable qnum has an initial value of 1. qnum will
be incremented later so that we can access the successive questions.
Recall that the TinyWebDB.GetValue call just requests the data from the web
service-- the value is not returned to the GetValue block directly. Instead,
when the data arrives to the phone from the web service, a
TinyWebDB.GotValue event is triggered. The blocks in that event-handler
will determine what the app does with the values returned from the
requests:
In the GotValue event, the app first checks to see if the value returned is the
empty string (has length of 0). If so, we know that our last request was for a
tag that doesn't exist in the tinywebdb web service database. This might
happen on our first request if no questions have ever been added, or it will
happen on the nth request if there are n-1 questions in the database.
If the value returned is empty, this means the loading of previously recorded
question-answer pairs is complete, so the app can enable the Submit button
so that the user can enter new entries.
If the value returned does not have a length of 0, the app has received a
valid question-answer pair, and the "else-do" blocks are executed. The first
thing those blocks do is add the question-answer pair returned into
ExistingLabel, which displays all of the question-answer pairs. A join is used
to concatenate the previous value of ExistingLabel with a newline character
("\n") and the new question-answer pair (valueFromWebDB). So if
ExistingLabel was showing:
What is the capital of California:Sacramento
and the newly accessed question was
What is the capital of Washington: Olympia
then the ExistingLabel label would be updated to:
What is the capital of California:Sacramento
What is the capital of Washington: Olympia
with the second question on a separate line due to the "\n".
Besides displaying the entry received from the database, the GotValue
event-handler must also request the next question (we only request the first
in the Initialize event). To do this, it increments qnum and requests the next
question from TinyWebDB.
Processing the Entry of New Question-Answer Pairs
The app also allows the user ("teacher") to enter new question-answer pairs.
The app has two textboxes, QuestionText and AnswerText, and a
SubmitButton. Recall that the GotValue event handler only enables the
SubmitButton when all the question-answers from the database have been
loaded, so the SubmitButton.Click event can only be triggered after that
process is complete. At that point, the variable qnum is set to the number of
questions that were in the database, e.g., 4. Here is the SubmitButton.Click
handler:
The SubmitButton.Click event handler first builds a new question-answer
pair by joining the user's input from QuestionText and AnswerText with a
colon in between. It then builds the tag as was done above with "WolbQuiz:"
joined with qnum, and calls TinyWebDB.StoreValue to store the new data. To
keep the list of question-answer pairs being displayed up-to-date, the
ExistingLabel is updated with the new entry.
Summary
With the TinyWebDB component, you can create apps that remember
things-- that store things in a database. Creating such an app requires you
to design how the data will be stored using the restricted key-value pairs
that TinyWebDB allows. You'll need a schemes such as was used in the quiz
app-- a list of items separated by ";;" with each field in the item separated
by "::". Then you'll need to program the blocks so that the data is inserted
and retrieved in that manner. Fortunately, the Text operations like join and
split make this relatively easy.
Problems
1. Create an application that stores your vote-- whatever you enter in a
textbox-- in the usfwebservice with a tag of your first name. The application
should also show you what you have previously entered (as in the sample).
2. Working with a partner or partners, have your app show the votes of
three or more people.
3. Write a quiz creator (teacher app) as described in this sample.
4. Write a quiz taker app. that lets the user take the quiz stored in the
database.

You might also like