HW 3
Kirk Scott
1
2
3
4
5
6
7
8
9
10
11
12
13
•
•
•
•
•
Flyweight
Decorator
State
Iterator
Template Method
14
• This set of homework overheads is different
from previous sets of homework overheads
• The homework assignment/checkoff sheet is
available as a separate document, as usual
• This set of overheads doesn’t repeat that
information
• Instead, it covers the background needed for
the state design pattern question on the
assignment
15
• What follows is the complete set of overheads
on the SillyString app
• This is the basis for the state design pattern
question
• Notice the bonus of getting both the pictures
for the assignment plus the pictures for the
SillyString overheads
16
Android 10: The Silly String App
Kirk Scott
17
18
19
20
21
22
23
Introduction
• The purpose of the Silly String app is to
illustrate some features that may be useful
when trying to do the calculator app
24
Outline
•
•
•
•
•
•
10.1
10.2
10.3
10.4
10.5
10.6
General Description
“cat” and “-->”
“dup”
“clear”
Valid Input
Activities, Focus, and State
25
• 10.7 Model, View, Controller
• 10.8 The Development Process and the
Components of Silly String
• 10.9 The Plan of Action
• 10.10 Layout XML
• 10.11 Java Code
26
10.1 General Description
• This document contains the specifications for
the Silly String app.
• A screen shot is given on the following
overhead, followed by textual explanations.
27
28
• The Silly String app allows you to enter two
strings formed from the 15 most common
letters in the English language, plus the
semicolon.
• The app’s most basic functionality is to display
the result of concatenating the two strings.
• The app has a miniature keypad style
keyboard built in.
29
• The boxes where text is displayed are not
editable, so a system supplied keyboard is not
used for input.
• In addition to the keyboard and input boxes,
the app has operator buttons and boxes to
show the results as well as any error messages
(the Log).
30
10.2 “cat” and “-->”
• The overall function of the app is to enter two
strings through the miniature keyboard,
concatenate them, and show the result.
• For this functionality, this is the logical sequence:
• 1. Phase 1: When the app starts, pressing letter
keys in succession will enter a sequence of
characters in the String1 box.
• 2. Phase 2: Pressing “cat” will cause pressing key
buttons in succession to enter a sequence of
characters in the String2 box.
31
• 3. Pressing “-->” will cause String1 and String2
to be concatenated and displayed in the
Result box.
• 4. The completion of the sequence should
return the app to Phase 1, where a new
String1 could be entered.
32
10.3 “dup”
• The app also has a duplication function.
• Observe that there are two active phases of the
app as described so far:
• i) When input goes to String1, and
• ii) When input goes to String2.
• The duplication function works in this way:
• 1. If the app is in Phase 1, pressing the “dup”
button will cause whatever is currently in String1
to be concatenated with itself and placed back in
String1.
33
• 2. If the app is in Phase 2, pressing the “dup”
button will cause whatever is currently in
String2 to be concatenated with itself and
placed back in String2.
• 3. Incidentally, in either of the two phases,
the “dup” button could be pressed more than
once, resulting in multiple duplications.
34
10.4 “clear”
• The “clear” button should have the effect of
blanking out the String1 and String2, Result, and
Log boxes in the app’s user interface.
• It should also have the effect of clearing any
internal variables/resources which correspond to
these boxes so that they are also blank.
• After pressing “clear” the app should begin
operation again in Phase 1, with no previous
actions having any effect on what happens next.
35
10.5 Valid Input
• There is a validation rule that applies to input
strings:
• A valid string can’t start with a semicolon and it
has to end with a semicolon.
• Validity checking will occur when the user presses
the “cat” or “-->” buttons.
• “cat” checks the validity of the contents of
String1.
• “-->” checks the validity of the contents of
String2.
36
• Incidentally, “dup” doesn’t check validity.
• In cases where invalid strings are found, the
app puts an error message into the Log box.
• Otherwise, it does nothing; it doesn’t blank
out bad strings, for example.
• It also doesn’t change state, from Phase1 to
Phase2 or back.
37
• That means that there are two alternatives for
the user:
• 1) Try to continue entering input for the
current string until the semicolon rules are
satisfied
• This works if the problem was a string that
didn’t end with a semicolon
• 2) Start over from scratch by pressing the
“clear” button.
38
10.6 Activities, Focus, and State
• Notice that this app will consist of a single
activity.
• As already noted, within the logic of the code,
two phases can be identified.
• In general, this means that the app has two
states.
39
• As you’ll see, state can be modeled by a
variable in code.
• Such a variable may be called a flag variable or
a state variable.
• The idea of state is related to the concept of
focus.
40
• The graphical user interface of an app may
have several components.
• Not all components are necessarily active at
the same time.
• The button, box, or other component which is
currently active, which the user can interact
with, is said to have focus.
41
• In other words, various components can be in
various states at various times.
• The Java and Android API’s have various
features which make it possible to manage
focus.
• In the Silly String app, the user interface
doesn’t have any focus complexities—
whichever button the user clicks will respond.
42
• However, internally, the app can be in
different states at different times.
• Whatever state the app is in, clicking buttons
on the keyboard will simply cause a sequence
of characters to appear in the box
corresponding to the current state.
• Clicking one of the operator buttons may
cause the state to change.
43
• The topic of state is not the main topic of this
app, but it’s a necessary part of it.
• You will encounter the concept of state in
other places as you continue to work with
software development.
44
• There is a relatively simple, visual way of
understanding state in an application, and it
may be helpful to you in understanding state
in this example.
• The visual representation of state in an app is
known as a state diagram or a transition
diagram.
45
• The idea is that the app can be in various
states at various times.
• And the app changes state based on actions
taken with it.
• In a diagram, the states that the app can be in
are represented by ovals.
• The actions are represented by arcs
connecting the boxes.
46
• In this app, there are two states, Phase1 and
Phase2.
• The actions which can change the state are
the “cat”, “-->”, and “clear” buttons.
• A diagram for the Silly String app is shown on
the following overhead:
47
clear
arrow
Start
Program
Phase1
cat
Phase2
arrow
clear
10.7 Model, View, Controller
• Model-View-Controller is the name of an objectoriented design pattern.
• The three terms in the name have these
meanings:
• 1. The model is that part of the code which
contains the state of the application.
• This refers to values like the strings which are
displayed in boxes, and in the case of Silly String,
it would also refer to a variable which
represented what phase the app was currently in.
49
• 2. The view is the graphical appearance of the
app on the screen.
• In other words, it’s the visual representation
of the app’s current state.
• As such, it is clear that through a combination
of programmer written code and system
supplied infrastructure, as the state of the app
is updated, the new state is what is shown.
50
• 3. The controller is that part of the app which
implements the logic of its functionality.
• In other words, this is the code for what the app
does.
• This is where the functional result of the app is
implemented
• It’s also the place where the programmer has to
keep track of and update state
• And it’s the place where the programmer takes
care of those aspects of updating the view which
the system doesn’t take care of.
51
• In various programming languages, like Java,
there are classes and methods and conventions
for implementing a graphical app using the
model-view-controller design pattern.
• There is a clear parallel between the structure of
Android and this design pattern.
• To a very great extent, the view elements of an
app are defined in the XML layout file resources.
52
• The state of an app is contained both in other
XML resources and in Java code variables or
structures.
• The controller logic is implemented in the Java
code of the activity or activities of the app.
53
• One of the challenges of Android is managing
the fact that the totality of an app is
subdivided into separate parts which are
contained in separate files which have to be
consistent with each other.
• The upside of this is that it is an effective way
to divide and conquer the task of coding an
app which has a graphical user interface.
54
10.8 The Development Process and
the Components of Silly String
• In general, recall that the development of an
app involves layouts, resources (such as
strings), and activity code.
• Managing things like string resources correctly
is important, but is not too complex.
• Those resources need to be defined, and the
correct syntax has to be used to access them.
55
• Layouts and activity code generally provide
more significant development challenges.
• The layout for Silly String will involve using
GridLayout and nested layouts containing
buttons and text boxes.
• The app has just one activity, so there is one
Java file for the code, main activity.
56
• Overall, the functionality of the code is not
highly complex.
• In a sense, it’s just one step beyond echoing.
• It consists of taking in input; doing something
relatively simple with the input; and showing
output.
• On the other hand, there will be a degree of
complexity in implementation:
57
• It will be necessary to keep track of the state
of the app
• It will be necessary to implement many
different listeners (sendMessage() methods)
for the many buttons in the app.
58
• This app goes back to the paradigm of one
sendMessage() method per button rather
than one method for many buttons
• There are many sendMessage() methods, but
they don’t have to contain if/else logic to
figure out which button was pressed
59
• In addition to the basic functionality of
concatenating and duplicating, validity
checking has to be implemented
• At various points, things like the presence or
absence of a semicolon have to be checked
before taking action
60
10.9 The Plan of Action
• The screen shot of Silly String is repeated on
the following overhead for reference.
61
62
• What follows are the contents of a
implementation of Silly String.
• The solution is given as layout and code,
illustrating a logical order for developing the
different files needed.
• The solution will provide concrete items which
may be adapted for use in solving other
problems and implementing other apps.
63
10.10 Layout XML
• The layout file for the app, activity_main.xml,
is given on the following overheads.
• You will notice an ellipsis (…) in it.
• There is no need to show all of the buttons
when their layout is the same.
• Among other things, this layout illustrates the
use of the GridLayout and the nesting of
layouts.
64
• <?xml version="1.0" encoding="utf-8"?>
<GridLayout
xmlns:android="http://schemas.android.com/apk
/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:useDefaultMargins="true"
android:alignmentMode="alignBounds"
android:columnOrderPreserved="false"
android:rowCount="4"
android:columnCount="4"
android:padding="20dp">
65
•
<GridLayout
android:layout_row="0"
android:layout_column="0"
android:rowCount="2"
android:columnCount="2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="String1:
"
android:layout_row="0"
android:layout_column="0"
android:typeface="serif" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/string1TextView"
android:layout_row="0"
android:layout_column="1"
android:typeface="monospace" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="String2:
"
android:layout_row="1"
android:layout_column="0"
android:typeface="serif" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/string2TextView"
android:layout_row="1"
android:layout_column="1"
android:typeface="monospace" />
</GridLayout>
66
•
<GridLayout
android:layout_row="0"
android:layout_column="1"
android:rowCount="2"
android:columnCount="2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Result:
"
android:layout_row="0"
android:layout_column="0"
android:typeface="serif" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/resultTextView"
android:layout_row="0"
android:layout_column="1"
android:typeface="monospace" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Log:
"
android:layout_row="1"
android:layout_column="0"
android:typeface="serif" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:id="@+id/logTextView"
android:layout_row="1"
android:layout_column="1"
android:typeface="monospace" />
</GridLayout>
67
•
•
•
<GridLayout
android:layout_row="1"
android:layout_column="0"
android:rowCount="4"
android:columnCount="4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="20dp">
<Button
android:text="e"
android:layout_row="0"
android:layout_column="0"
android:minHeight="0dp"
android:minWidth="0dp"
android:onClick="sendMessageE"
/>
<Button
android:text="t"
android:layout_row="0"
android:layout_column="01"
android:minHeight="0dp"
android:minWidth="0dp"
android:onClick="sendMessageT"
/>
…
/>
<Button
android:text="w"
android:layout_row="3"
android:layout_column="2"
android:minHeight="0dp"
android:minWidth="0dp"
android:onClick="sendMessageW"
/>
<Button
android:text=";"
android:layout_row="3"
android:layout_column="3"
android:minHeight="0dp"
android:minWidth="0dp"
android:onClick="sendMessageSemicolon"
/>
</GridLayout>
68
•
<GridLayout
android:layout_row="1"
android:layout_column="1"
android:rowCount="2"
android:columnCount="2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="20dp">
<Button
android:text="cat"
android:layout_row="0"
android:layout_column="0"
android:minHeight="0dp"
android:minWidth="0dp"
android:onClick="sendMessageCat"
/>
<Button
android:text="-->"
android:layout_row="0"
android:layout_column="1"
android:minHeight="0dp"
android:minWidth="0dp"
android:onClick="sendMessageArrow"
/>
<Button
android:text="dup"
android:layout_row="1"
android:layout_column="0"
android:minHeight="0dp"
android:minWidth="0dp"
android:onClick="sendMessageDup"
/>
<Button
android:text="clear"
android:layout_row="1"
android:layout_column="1"
android:minHeight="0dp"
android:minWidth="0dp"
android:onClick="sendMessageClear"
/>
</GridLayout>
</GridLayout>
69
10.11 Java Code
• The Java file for the app, MainActivity.java, is
shown on the following overheads.
• You will notice an ellipsis (…) in it.
• There is no need to show the sendMessage()
method for all of the buttons when their
implementation is the same.
• Notice that the state variable is declared at the
top of the class, and notice the calls in some of
the methods which cause the state of the app to
change.
70
•
package com.example.kascott.sillystring;
import
import
import
import
import
android.content.Intent;
android.support.v7.app.AppCompatActivity;
android.os.Bundle;
android.view.View;
android.widget.TextView;
public class MainActivity extends AppCompatActivity {
/* This is the state variable. The initial state of the app
is Phase1. This
* means that data entry from the built-in keyboard will be
appended to the
* String1 box. */
String state = "Phase1"; //"Phase1";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
71
•
public void sendMessageE(View view) {
if (state.equals("Phase1")) {
TextView myString1TextView = (TextView) findViewById(R.id.string1TextView);
String stringContents = (String) myString1TextView.getText();
stringContents = stringContents + "e";
myString1TextView.setText(stringContents);
}
else if (state.equals("Phase2")) {
TextView myString2TextView = (TextView) findViewById(R.id.string2TextView);
String stringContents = (String) myString2TextView.getText();
stringContents = stringContents + "e";
myString2TextView.setText(stringContents);
}
else
{
TextView myTextView = (TextView) findViewById(R.id.logTextView);
myTextView.setText("Fatal state error.");
}
}
public void sendMessageT(View view) {
if (state.equals("Phase1")) {
TextView myString1TextView = (TextView) findViewById(R.id.string1TextView);
String stringContents = (String) myString1TextView.getText();
stringContents = stringContents + "t";
myString1TextView.setText(stringContents);
}
else if (state.equals("Phase2")) {
TextView myString2TextView = (TextView) findViewById(R.id.string2TextView);
String stringContents = (String) myString2TextView.getText();
stringContents = stringContents + "t";
myString2TextView.setText(stringContents);
}
else
{
TextView myTextView = (TextView) findViewById(R.id.logTextView);
myTextView.setText("Fatal state error.");
}
}
•
…
72
•
public void sendMessageW(View view) {
if (state.equals("Phase1")) {
TextView myString1TextView = (TextView) findViewById(R.id.string1TextView);
String stringContents = (String) myString1TextView.getText();
stringContents = stringContents + "w";
myString1TextView.setText(stringContents);
}
else if (state.equals("Phase2")) {
TextView myString2TextView = (TextView) findViewById(R.id.string2TextView);
String stringContents = (String) myString2TextView.getText();
stringContents = stringContents + "w";
myString2TextView.setText(stringContents);
}
else
{
TextView myTextView = (TextView) findViewById(R.id.logTextView);
myTextView.setText("Fatal state error.");
}
}
public void sendMessageSemicolon(View view) {
if (state.equals("Phase1")) {
TextView myString1TextView = (TextView) findViewById(R.id.string1TextView);
String stringContents = (String) myString1TextView.getText();
stringContents = stringContents + ";";
myString1TextView.setText(stringContents);
}
else if (state.equals("Phase2")) {
TextView myString2TextView = (TextView) findViewById(R.id.string2TextView);
String stringContents = (String) myString2TextView.getText();
stringContents = stringContents + ";";
myString2TextView.setText(stringContents);
}
else
{
TextView myTextView = (TextView) findViewById(R.id.logTextView);
myTextView.setText("Fatal state error.");
}
}
73
•
public void sendMessageCat(View view) {
TextView myString1TextView = (TextView) findViewById(R.id.string1TextView);
String stringContents = (String) myString1TextView.getText();
String firstCharacter = stringContents.substring(0, 1);
int lastIndex = stringContents.length() - 1;
int pastEnd = stringContents.length();
String lastCharacter = stringContents.substring(lastIndex, pastEnd);
if(firstCharacter.equals(";") || !lastCharacter.equals(";")) {
TextView myTextView = (TextView) findViewById(R.id.logTextView);
myTextView.setText("Problem with semicolon input.");
}
else {
state = "Phase2";
}
}
public void sendMessageArrow(View view) {
TextView myString2TextView = (TextView) findViewById(R.id.string2TextView);
String stringContents2 = (String) myString2TextView.getText();
String firstCharacter = stringContents2.substring(0, 1);
int lastIndex = stringContents2.length() - 1;
int pastEnd = stringContents2.length();
String lastCharacter = stringContents2.substring(lastIndex, pastEnd);
if(firstCharacter.equals(";") || !lastCharacter.equals(";")) {
TextView myTextView = (TextView) findViewById(R.id.logTextView);
myTextView.setText("Problem with semicolon input.");
}
else {
TextView myString1TextView = (TextView) findViewById(R.id.string1TextView);
String stringContents1 = (String) myString1TextView.getText();
String output = stringContents1 + stringContents2;
TextView myResult = (TextView) findViewById(R.id.resultTextView);
myResult.setText(output);
state = "Phase1";
}
}
74
•
public void sendMessageDup(View view) {
if (state.equals("Phase1")) {
TextView myString1TextView = (TextView) findViewById(R.id.string1TextView);
String stringContents = (String) myString1TextView.getText();
stringContents = stringContents + stringContents;
myString1TextView.setText(stringContents);
}
else if (state.equals("Phase2")) {
TextView myString2TextView = (TextView) findViewById(R.id.string2TextView);
String stringContents = (String) myString2TextView.getText();
stringContents = stringContents + stringContents;
myString2TextView.setText(stringContents);
}
}
public void sendMessageClear(View view) {
TextView myString1TextView = (TextView) findViewById(R.id.string1TextView);
myString1TextView.setText("");
TextView myString2TextView = (TextView) findViewById(R.id.string2TextView);
myString2TextView.setText("");
TextView resultTextView = (TextView) findViewById(R.id.resultTextView);
resultTextView.setText("");
TextView logTextView = (TextView) findViewById(R.id.logTextView);
logTextView.setText("");
state = "Phase1";
}
}
75
Summary and Mission—This is Taken from
the Android Set of Overheads. It Doesn’t
Apply to Design Patterns.
• The purpose of the Silly String app is to
illustrate some features that may be useful
when trying to do the calculator app
• Needless to say, there is a lot included in the
calculator app that is not included in Silly
String
• The calculator app assignment is the topic of
the next set of overheads
• Stay tuned
76
The End
77
The End
78
© Copyright 2026 Paperzz