Download presentation
Presentation is loading. Please wait.
1
Android 10: The Silly String App
Kirk Scott
8
Introduction The purpose of the Silly String app is to illustrate some features that may be useful when trying to do the calculator app
9
Outline 10.1 General Description 10.2 “cat” and “-->” 10.3 “dup”
10.4 “clear” 10.5 Valid Input 10.6 Activities, Focus, and State
10
10.7 Model, View, Controller 10.8 The Development Process and the Components of Silly String 10.9 The Plan of Action Layout XML Java Code
11
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.
13
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.
14
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).
15
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.
16
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.
17
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.
18
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.
19
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.
20
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.
21
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.
22
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.
23
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. 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.
24
The idea of state is related to the concept of focus.
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.
25
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.
26
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.
27
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.
28
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.
29
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.
30
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:
31
arrow clear Start Program cat Phase1 Phase2 arrow clear
32
10.7 Model, View, Controller Model-View-Controller is the name of an object-oriented 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.
33
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.
34
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. In addition to whatever the functional result of the app is, the code is also the place where the programmer has to keep track of and update state, as taking care of those aspects of updating the view which the system doesn’t take care of.
35
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.
36
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.
37
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.
38
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.
39
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 Java code for the app will be monolithic, because there’s just one activity.
40
Overall, the functionality of the code is not highly complex
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:
41
It will be necessary to keep track of the state of the app and it will be necessary to implement many different listeners (sendMessage() methods) for the many buttons in the app. I prefer the paradigm of one listener per button rather than one listener for many buttons, where the listener then has to determine which button was pressed. And along with this, validity checking will have to be implemented.
42
10.9 The Plan of Action What follows are the contents of a implementation of Silly String, as reflected in the screen shot given at the beginning of this document. 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.
43
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.
44
<. xml version="1. 0" encoding="utf-8"
<?xml version="1.0" encoding="utf-8"?> <GridLayout xmlns: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">
45
<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: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:layout_row="1" android:layout_column="1" android:typeface="monospace" /> </GridLayout>
46
<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: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:layout_row="1" android:layout_column="1" android:typeface="monospace" /> </GridLayout>
47
<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>
48
<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>
49
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.
50
package com. example. kascott. sillystring; import android. content
package com.example.kascott.sillystring; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import 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); }
51
public void sendMessageE(View view) { if (state
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."); } } …
52
public void sendMessageW(View view) { if (state
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."); } }
53
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"; } }
54
public void sendMessageDup(View view) { if (state
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"; } }
55
Summary and Mission The purpose of the Silly String app is to illustrate some features that may be useful when trying to do the calculator app Your mission is to begin work on the calculator app Needless to say, there is a lot included in the calculator app that is not included in Silly String
56
The End
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.