114
Android 5: Wari 1

Android 5: Wari

  • Upload
    lainey

  • View
    67

  • Download
    0

Embed Size (px)

DESCRIPTION

Android 5: Wari. Introduction. This set of overheads is more than just Wari It begins with a simple app where the sendMessage () method is small, but contains some significant code It is a lead-in to debugging As soon as code gets more complicated you have to be able to debug - PowerPoint PPT Presentation

Citation preview

Page 1: Android 5:   Wari

1

Android 5: Wari

Page 2: Android 5:   Wari

2

Page 3: Android 5:   Wari

3

Introduction

• This set of overheads is more than just Wari• It begins with a simple app where the

sendMessage() method is small, but contains some significant code

• It is a lead-in to debugging• As soon as code gets more complicated you

have to be able to debug• It is also a lead-in to the code for Wari

Page 4: Android 5:   Wari

4

• Wari illustrates both code logic and a more complicated layout

• There are two perspectives on what’s going on:• First of all, it should be apparent that things are easier

because GUI layout work is separate from the Java code

• On the other hand, in order to deal with this separation between logic and layout, the implementation of Wari will differ significantly from implementations you’ve seen before

Page 5: Android 5:   Wari

5

• 5.1 The OneButtonRecursion app• 5.2 Unhelpful Error Messages• 5.3 Logging Output• 5.4 Wari—General Remarks• 5.5 layout.xml for Wari• 5.6 strings.xml for Wari• 5.7 R.java for Wari• 5.8 MainActivity.java for Wari

Page 6: Android 5:   Wari

6

5.1 The OneButtonRecursion app

• The OneButtonRecursion app will be presented in the order in which it was developed:

• 1. activity_main.xml, the layout• 2. strings.xml, the resources• 3. Look at R.java, the resources as made

available by the system• 4. MainActivity.java, the code for the app

Page 7: Android 5:   Wari

7

• As you might guess, part of what makes the app interesting is the fact that it includes recursion

• This is a preview of the fact that recursion will be used in the implementation of Wari

Page 8: Android 5:   Wari

8

• The other thing that makes the app interesting, and relevant to Wari, is that the contents of the text view are changeable, and are treated as an integer

• This introduces some syntax, which in turn, introduces the possibility of errors

• These errors turn out to be runtime errors, so it behooves us to consider the topic of debugging in Android

Page 9: Android 5:   Wari

9

activity_main.xml for OneButtonRecursion

• A screenshot of the layout of the OneButtonRecursion app in the development environment is shown on the following overhead

• It is a simple layout, containing a button and a text view

Page 10: Android 5:   Wari

10

Page 11: Android 5:   Wari

11

• This app happens to use relative layout• There is nothing particularly striking about the

syntax for that• The XML code for the layout is given on the

following overheads for reference

Page 12: Android 5:   Wari

12

• <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

• xmlns:tools="http://schemas.android.com/tools"• android:layout_width="match_parent"• android:layout_height="match_parent"• android:paddingBottom="@dimen/activity_vertical_margin"• android:paddingLeft="@dimen/activity_horizontal_margin"• android:paddingRight="@dimen/activity_horizontal_margin"• android:paddingTop="@dimen/activity_vertical_margin"• tools:context=".MainActivity" >

Page 13: Android 5:   Wari

13

• <Button• android:id="@+id/button1"• style="?android:attr/buttonStyleSmall"• android:layout_width="wrap_content"• android:layout_height="wrap_content"• android:layout_alignParentLeft="true"• android:layout_alignParentTop="true"• android:text="@string/button1Contents"• android:onClick="sendMessage" />

Page 14: Android 5:   Wari

14

• <TextView• android:id="@+id/textView1"• android:layout_width="wrap_content"• android:layout_height="wrap_content"• android:layout_alignBaseline="@+id/button1"• android:layout_alignBottom="@+id/button1"• android:layout_toRightOf="@+id/button1"• android:text="@string/textView1Contents" /> • • </RelativeLayout>

Page 15: Android 5:   Wari

15

• There were some items in the XML that haven’t come up before

• Where did they come from?• If you use the graphical tools to create the

basic layout, the system will generate the XML• You can then edit the XML, if necessary, to

tailor the layout to the specific app you’re trying to create

Page 16: Android 5:   Wari

16

strings.xml for OneButtonRecursion

• The strings.xml file for the app is shown on the following overhead

• There are no surprises• The button and the text view have string

resources associated with them

Page 17: Android 5:   Wari

17

• <?xml version="1.0" encoding="utf-8"?>• <resources>

• <string name="app_name">One Button Recursion</string>• <string name="action_settings">Settings</string>• <string name="hello_world">Hello world!</string>• <string name="button1Contents">Button1</string>• <string name="textView1Contents">4</string> • • </resources>

Page 18: Android 5:   Wari

18

R.Java for OneButtonRecursion

• As you recall, the R.java file is generated for you

• It’s important because it’s the place where you can access resources when writing the Java code for MainActivity

• The relevant parts of R.java are shown on the following overhead

Page 19: Android 5:   Wari

19

• public static final class id {• …• public static final int button1=0x7f080000;• public static final int textView1=0x7f080001;• }• …• }• public static final class string {• …• public static final int button1Contents=0x7f050003;• public static final int textView1Contents=0x7f050004;

Page 20: Android 5:   Wari

20

MainActivity.java for OneButtonRecursion

• The logic of OneButtonRecursion is quite simple

• The TextView is initially set to a value of 4• When you click the button, you call

sendMessage()

Page 21: Android 5:   Wari

21

• sendMessage() checks to see what the current value is

• If the value is >0, then a call is made to a method named playNextCup() and the value is passed in

Page 22: Android 5:   Wari

22

• playNextCup() decrements the value• It updates the text area to this new value• If the value has not yet reached 0, it calls itself

recursively• The end result of this sequence of actions is that

the value in the text view goes 4, 3, 2, 1, 0—too fast for the eye to see

• One click of the button causes the text view to go from 4 to 0, recursively

Page 23: Android 5:   Wari

23

• The logic is simple, but the code will look needlessly complex

• It repeatedly gets a handle on the text view and passes this around—which is needless, considering there is only one text area

• It also includes if statements to check “which button was clicked” when there is only one button

Page 24: Android 5:   Wari

24

• The code is written in this way because it is a preview of what will have to be done to implement Wari

• It is clumsy here, but it’s easier to first get an idea of what’s involved in a mindless recursion program with only one text view and one button

Page 25: Android 5:   Wari

25

• Then, in an app with >1 text view and button, it becomes apparent that it is necessary to repeatedly get references and pass them around and check which button was clicked

Page 26: Android 5:   Wari

26

An Import and a Declaration and Initialization for Debugging

• The import of the Log class and the TAG string definition shown here will be useful for logging and debugging

• They come at the beginning of the MainActivity class, so they are shown now

• Further explanations will be given later

• import android.util.Log;

• public class MainActivity extends Activity {

• private static final String TAG = "OneButtonRecursion";

• …

Page 27: Android 5:   Wari

27

sendMessage() for OneButtonRecursion

• The code for sendMessage() is shown on the following overhead

• Note that the calls to findViewById() and playNextCup() are floating in space

• They are calls on the MainActivity itself• The concept of activities is important and will

be pursued further in later sets of overheads

Page 28: Android 5:   Wari

28

• public void sendMessage(View view) {• Button clickedButton = (Button) view;

• if(clickedButton == findViewById(R.id.button1))• {• TextView cup = (TextView) findViewById(R.id.textView1);• int handFull = Integer.parseInt(cup.getText().toString());

• if(handFull > 0)• {• cup.setText(handFull + "");• playNextCup((TextView) findViewById(R.id.textView1),

handFull);• }

• }

• else• {• }• }

Page 29: Android 5:   Wari

29

playNextCup() for OneButtonRecursion

• playNextCup() contains the recursive call• It also contains the uses of Log and TAG• These will be explained in a moment

Page 30: Android 5:   Wari

30

• public static void playNextCup(TextView cupIn, int handFullIn)

• {• handFullIn--;• cupIn.setText(handFullIn + "");

• if(handFullIn != 0)• {• playNextCup(cupIn, handFullIn);• Log.i(TAG, "In recursion " + handFullIn);• }• else• {• }• }

Page 31: Android 5:   Wari

31

5.2 Unhelpful Error Messages

• When writing the code even for this simple app, I made mistakes (go figure)

• It quickly became apparent that I would need to be able to debug in the Android environment

• I’m not referring now to the debugging tools in Eclipse—they’re beyond the scope of this course

• I’m referring to simply figuring out what was going on

Page 32: Android 5:   Wari

32

• Compiler errors are shown at the bottom of the screen under the “Problems” tab, and they’re marked in red there and flagged in your code

• You will find that Eclipse has a helpful “Quick Fix” tool that frequently tells you pretty clearly what’s wrong and how to fix it

• These things are illustrated on the following overhead

Page 33: Android 5:   Wari

33

Page 34: Android 5:   Wari

34

• I also got two good (bad) examples with OneButtonRecursion of what can go more seriously wrong and the quandary you’re left in

• These were runtime errors, and they illustrated two features of the development environment

Page 35: Android 5:   Wari

35

• 1. In Java programming, you may be used to the fact that even runtime errors show the line numbers in your code where the errors occur

• This does not appear to be the case with Android

• You do see a trace of calls, but it’s up to you to figure out where that trace intersects your code and the exact location of the problem

Page 36: Android 5:   Wari

36

• 2. The second aspect accounts for the heading of this section

• Like with many systems, the error messages are not necessarily helpful

• As usual, being able to look the error message up on the Web was very helpful in trying to figure out what it meant

Page 37: Android 5:   Wari

37

Example 1

• Here is a snippet of code that’s in error:

• int handFull = Integer.parseInt(cup.getText().toString());• …• cup.setText(handFull);

• Here is the error message you get:

• No package identifier when getting value for resource number HideousHexValue

Page 38: Android 5:   Wari

38

• This is not helpful• It seems to suggest some deep problem with

the use of resources (like the values in R.java) or maybe with passing parameters, like the activity, around

• It doesn’t identify which method call is the source of the problem

Page 39: Android 5:   Wari

39

• The explanation turns out to be much simpler• When writing the incorrect code, I heedlessly

assumed that setText() converted whatever parameter was sent to it to a string by an internal call to toString()

• This is not so• There is a version of setText() which accepts an

integer parameter, where the integer is the id for a resource

Page 40: Android 5:   Wari

40

• The value contained in handFull doesn’t agree with any defined resource id value, so the system has a runtime problem

• (Imagine the fun you’d have if, by accident, handFull did contain a valid resource id, and you got inexplicable results instead of a runtime error)

Page 41: Android 5:   Wari

41

• In any case, once you know what’s wrong, the solution is simple

• This is the corrected code:

• int handFull = Integer.parseInt(cup.getText().toString());• …• cup.setText(handFull + “”);

Page 42: Android 5:   Wari

42

Example 2

• The same two lines of code contain a call that can also generate another unhelpful runtime error

• int handFull = Integer.parseInt(cup.getText().toString());• …• cup.setText(handFull + “”);

• Consider the call to parseInt()• parseInt() will fail if you apply it to a string that

can’t be parsed as an integer

Page 43: Android 5:   Wari

43

• If you write the code as shown and the text view you’re getting the string from doesn’t contain an integer

• You will get this runtime error message:

• FATAL EXCEPTION: main java.lang.IllegalStateException

• It sounds grievous, doesn’t it?

Page 44: Android 5:   Wari

44

• The tracing of calls that’s presented eventually reaches the parseInt() call, but it’s not immediately apparent what it is about that call that’s causing such a serious problem

• The error message obviously doesn’t tell you something simple, like the parameter passed to the method isn’t right

Page 45: Android 5:   Wari

45

• This kind of problem is the result of simple carelessness in coding

• A runtime error can be avoided by careful coding or by putting the call in a try catch block

• As a garden variety programmer, I made the mistake

• Because the error message wasn’t helpful, I had to sort this out with old fashioned debugging, the topic of the next section

Page 46: Android 5:   Wari

46

5.3 Logging Output

• A screenshot of the current example is shown on the following overhead

• The playNext() method is shown in the editor• The LogCat tab has been selected at the

bottom• This shows the non-graphical output of the

app

Page 47: Android 5:   Wari

47

Page 48: Android 5:   Wari

48

• In order to do simple debugging, you need to be able to print output strings from your code, like calling System.out.println() in Java code

• The Android system will write to LogCat• The programmer can also send non-graphical

output there

Page 49: Android 5:   Wari

49

• These are the lines of code in the application related to logging

• import android.util.Log;

• public class MainActivity extends Activity {

• private static final String TAG = "OneButtonRecursion";• …• Log.i(TAG, "In recursion " + handFullIn);

Page 50: Android 5:   Wari

50

• In order to write to LogCat you need to import the Log class

• Log contains static methods, like “i”, which stands for “information” (as opposed to println() for System.out)

• These log methods take two strings as parameters, a tag, and the actual output

Page 51: Android 5:   Wari

51

• It’s simplest to just define a TAG so that every line from a given app is clearly identified in the LogCat

• Then at strategic places put calls to Log.i() to see what’s happening

• Eclipse has fancier debugging tools, but I’ve always done it by hand in this way

Page 52: Android 5:   Wari

52

An Example

• On the following overhead is a block of code that gave me a runtime error

• As noted earlier, the runtime error messages are not always as helpful as they might be

• You’re not told which line of code caused the runtime error

• I couldn’t tell what exactly was wrong—it was the highlighted parseInt() call

Page 53: Android 5:   Wari

53

• TextView capturedCup = (TextView) activityIn.findViewById(R.id.textView16);

• int capturedCount = Integer.parseInt(capturedCup.getText().toString());

• capturedCount += seedCount;

• capturedCup.setText(capturedCount + "");

Page 54: Android 5:   Wari

54

• The code on the following overhead shows how I picked the block apart and was able to identify exactly which line and which call was causing the problem

Page 55: Android 5:   Wari

55

• /* Debugging code */• /*• Log.i(TAG, "1");

• TextView capturedCup = (TextView) activityIn.findViewById(R.id.textView16);

• Log.i(TAG, "2, capturedCup id: " + capturedCup);

• CharSequence tempText = capturedCup.getText();

• Log.i(TAG, "3");

• String tempString = tempText.toString();

• Log.i(TAG, "4, tempString contents of capturedCup: " + tempString);

• int capturedCount = Integer.parseInt(tempString);

• Log.i(TAG, "5");

• capturedCount += seedCount;

• Log.i(TAG, "6");

• capturedCup.setText("x"); //(capturedCount + "");

• Log.i(TAG, "7");• */

Page 56: Android 5:   Wari

56

5.4 Wari—General Remarks

Page 57: Android 5:   Wari

57

Wari in CSCE 202

• Obviously, the point of using Wari as an example is that it needs no introduction

• For those who didn’t take CSCE 202 from me, go to the link for that course on my Web page for full information

• May the tutelary deities of Wari be your guide

Page 58: Android 5:   Wari

58

Page 59: Android 5:   Wari

59

Page 60: Android 5:   Wari

60

• You may recall these characteristics of the implementation of Wari in CSCE 202

• There was a Cup class• The board consisted of an array of cups• Each cup contained a reference to the next

cup, so they were linked together in circular fashion, the way play progressed around the board

Page 61: Android 5:   Wari

61

• The cups also had text fields• In assembling the overall graphical user

interface for the application, the text fields belonging to the cups were presented in panels on the screen

• The design was approaching a model-view-controller design, but it’s true that components were still tightly integrated

Page 62: Android 5:   Wari

62

• In Java, with the information given in CSCE 202, it was not so hard to simply create a “dead” graphical user interface, with all of the visual components displayed on the screen but no functionality

• The purpose of this brief review is remind you of the issues of layout, design, and functionality as they were introduced when working with Java swing

Page 63: Android 5:   Wari

63

Wari in Android

• As you have already seen, although based on Java code, the tools for Android app design are different

• This is a simple description of the plan for developing Android apps:

• Using widgets, develop a graphical layout (activity_main.xml)

• Acquire handles on these widgets through R.java• Use these widgets in your Java code,

MainActivity.java

Page 64: Android 5:   Wari

64

• The widgets and their layout are separately defined in their own XML file

• They have a life of their own independent of the MainActivity.java source file

• In other words, there’s been no indication so far that an Android version of Wari would mimic the straight Java implementation

Page 65: Android 5:   Wari

65

• Although it may be possible, there’s been no consideration of the following:

• Constructing arrays of widgets• Devising application classes where instance variables

of those classes are widgets• Trying to link widgets or objects containing them

together• In fact, you can do swing-like things in an Android app,

but it is not the default approach, and it can be counterproductive

Page 66: Android 5:   Wari

66

• The goal of the Wari example given in this set of overheads is to implement roughly the same functionality as the swing version in Java

• But the intention is not to try and duplicate the earlier implementation, where the game logic and the graphical view were integrated into the same Java code

Page 67: Android 5:   Wari

67

• The goal is to take the default Android approach and implement the same functionality while leaving the widgets as independent graphical items in the interface

• The implementation will still use buttons for play• This introduces another Android constraint:• There will be one sendMessage() method for the

app• It will handle clicks from all of the buttons in the GUI

Page 68: Android 5:   Wari

68

Implementation Approach

• The fundamental beginning step in Wari is picking a cup to play

• If the cup contains seeds, you then move to the next cup

• The description so far implies that in the Android app, the widgets representing the cups won’t be linked

Page 69: Android 5:   Wari

69

• If the cups aren’t linked together by references, how can you implement moving from one cup to another in this way?

• The cups can be linked together functionally, by logic in the method that is called when a button is clicked to play a cup

Page 70: Android 5:   Wari

70

• The method needs to identify the cup that was clicked

• The method code will contain a sequence of if/else if statements that encapsulate this logic, hardcoding the id’s of the cups:

• If you’re on cup x, the next cup is y; else if you’re on cup y, the next cup is z; and so on, all the way around the board

Page 71: Android 5:   Wari

71

• You can progress around the board as far as needed and no further by doing recursion on the value of handFull that you pick up in the first cup

• (Note the similarity with simple example given earlier)

• The stopping condition is easy and natural:• When the handFull is empty (== 0) you’re done

Page 72: Android 5:   Wari

72

Coming Attractions

• This unit contains the first assignment, where you’re expected to implement something Wari-like as an Android app

• In the following sections, further explanations will be given of how to do this, some example code will be shown, but complete code will not be given or posted

Page 73: Android 5:   Wari

73

• It will be up to you to fill in the missing spaces and get it to work

• I know it can be done because I did it• The incomplete example work you’re being

shown consists of selections from the code of a working app

Page 74: Android 5:   Wari

74

5.5 layout.xml for Wari

• Step 1: Create a layout that presents a Wari-like interface with the necessary components

• I used buttons for play and text views to hold the contents of cups

• I decided to use a table layout• Android has something called a grid layout, but

it’s not exactly the same as a Java grid layout• The Android table layout is similar to a Java grid

layout

Page 75: Android 5:   Wari

75

• I decided that it would be helpful to use the graphical tools in Android rather than trying to master the XML syntax

• This was not trouble-free

Page 76: Android 5:   Wari

76

• More than once I had to start over and create components in a different order so that the default names they received would be consistent with the logic of their use in my code

• There were 12 buttons and 12 text views in the layout

• I wanted them numbered 1-12 in the order they would be played in the game

Page 77: Android 5:   Wari

77

• I also discovered that my machine was underpowered or something

• Some of the tools caused my system to crash• The main lesson there was don’t touch those

tools• I tried to upgrade to a different machine, but it

was impossible to install the Google driver, so I was stuck with the lesser of two evils

Page 78: Android 5:   Wari

78

• The following overhead shows a screenshot of my layout in the development environment

• I’m showing you this in order to remind you of the graphical tools

• My layout consisted entirely of text view and small buttons

• Notice that among the tools is an option to choose a layout

• This is where I found the table layout

Page 79: Android 5:   Wari

79

Page 80: Android 5:   Wari

80

• The following overheads show the XML code that was generated up through the first row of the table layout

• The full file goes on at length• This is where you can check to see what default

names your widgets are being given• They are numbered in creation order• Your code doesn’t have to be the same, but it will

at least be similar

Page 81: Android 5:   Wari

81

• <?xml version="1.0" encoding="utf-8"?>• <!-- This is the activity_main.xml file for Wari. -->• <LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"• android:layout_width="fill_parent"• android:layout_height="fill_parent"• android:orientation="vertical" >

• <TextView• android:id="@+id/textView13"• android:layout_width="wrap_content"• android:layout_height="wrap_content"• android:text="@string/textView13Contents" />

• <TextView• android:id="@+id/textView14"• android:layout_width="wrap_content"• android:layout_height="wrap_content"• android:text="@string/textView14Contents" />

Page 82: Android 5:   Wari

82

• <TableLayout• android:layout_width="match_parent"• android:layout_height="wrap_content" >

• <TableRow• android:id="@+id/tableRow1"• android:layout_width="wrap_content"• android:layout_height="wrap_content" >

• <Button• android:id="@+id/button1"• style="?android:attr/buttonStyleSmall"• android:layout_width="wrap_content"• android:layout_height="wrap_content"• android:text="@string/button1Contents"• android:onClick="sendMessage" />

• <TextView• android:id="@+id/textView1"• android:layout_width="wrap_content"• android:layout_height="wrap_content"• android:text="@string/textView1Contents" />

Page 83: Android 5:   Wari

83

• <TextView• android:id="@+id/filler1"• android:layout_width="wrap_content"• android:layout_height="wrap_content"• android:text="@string/filler" /> • • <TextView• android:id="@+id/textView12"• android:layout_width="wrap_content"• android:layout_height="wrap_content"• android:text="@string/textView12Contents" />

• <Button• android:id="@+id/button12"• style="?android:attr/buttonStyleSmall"• android:layout_width="wrap_content"• android:layout_height="wrap_content"• android:text="@string/button12Contents"• android:onClick="sendMessage" />

Page 84: Android 5:   Wari

84

5.6 strings.xml for Wari

• Creating a strings.xml file for an app isn’t too difficult

• Largely you can just copy the layout.xml file as your starting point and then edit it

• It already contains all of the named items that were created in the layout that are referred to in strings.xml

• The first step is deleting all of the layout specific stuff surrounding these names

Page 85: Android 5:   Wari

85

• In strings.xml you give these named items initial values

• You replace the stuff you removed with the right syntax for a strings.xml file

• You can also add any other strings necessary for your app

• A subset of the code for strings.xml for Wari is shown on the following overhead

Page 86: Android 5:   Wari

86

• <?xml version="1.0" encoding="utf-8"?>• <resources>

• <string name="app_name">Wari</string>• <string name="action_settings">Settings</string>• <string name="button1Contents">P1, C1</string>• <string name="button2Contents">P1, C2</string>• …

• <string name="textView1Contents">4</string>• <string name="textView2Contents">4</string>• …

• <string name="filler">" "</string>

• </resources>

Page 87: Android 5:   Wari

87

• What I’m saying is that you start with something like this:

• <TextView• android:id="@+id/textView1"• android:layout_width="wrap_content"• android:layout_height="wrap_content"•

android:text="@string/textView1Contents" />

• And you use it as the starting point to make this, for example:

• <string name="textView1Contents">4</string>

Page 88: Android 5:   Wari

88

5.7 R.java for Wari

• As you recall, R.java is auto-generated• If your layout and strings files were complete,

R.java will have everything you need in it• The point is that when writing the code for

MainActivity.java, you refer to R.java• A subset of R.java is shown on the following

overhead

Page 89: Android 5:   Wari

89

• …• public final class R {• …• public static final class id {• public static final int

action_settings=0x7f080028;• public static final int button1=0x7f080003;• public static final int button10=0x7f080013;• public static final int button11=0x7f08000d;• public static final int button12=0x7f080007;• public static final int button2=0x7f080009;

Page 90: Android 5:   Wari

90

5.8 MainActivity.java for Wari

• There is nothing special about the onCreate() and onCreateOptionsMenu() methods for Wari

• They’re just copied as usual• There’s also nothing unusual about the imports• Some need to be added so that the code can

work with various classes, but they won’t be detailed

• The logic of the app is in the sendMessage() and playNextCup() methods

Page 91: Android 5:   Wari

91

sendMessage() for Wari

• As always, sendMessage() is the method called on a button click

• This is critically important to this application:• Each of the 12 buttons in Wari is linked to the

one sendMessage() method

Page 92: Android 5:   Wari

92

• This goes back to a discussion that occurs at the end of CSCE 202

• You may recall that it’s possible to have one event and many listeners

• It’s also possible to have many events and one listener

Page 93: Android 5:   Wari

93

• You may also recall that in the development of Wari in swing, the possibility of having a listener full of if statements was mentioned in passing and rejected as not the ideal solution

• We have now come full circle• sendMessage() is like a common listener for

clicks on multiple different buttons

Page 94: Android 5:   Wari

94

• sendMessage() determines which button was clicked

• There is then a series of if statements• In each if statement, effectively the same logic

is implemented• The different cases only differ by which

button/cup/next cup are involved

Page 95: Android 5:   Wari

95

• Not only is this method the one listener for all of the buttons

• This is the part of the app code that creates the functional connection between the different, independent widgets in the app

• In other words, sendMessage() functionally implements the structure of the game board

• The sendMessage() method calls the playNextCup() method, which implements the logic of playing the game

Page 96: Android 5:   Wari

96

• The if/else if code in sendMessage() is highly redundant

• No claim is made that this is the ideal solution• It is presented as a quick and dirty approach

which is relatively easy to understand in the context of Android widgets

• The redundancy actually makes it easy to write• You just copy and paste and change the numbers

identifying the buttons and cups

Page 97: Android 5:   Wari

97

• The first two if cases for the sendMessage() method are shown on the following overhead

• The full method just continues the pattern• If you need more knowledge in order to

understand what’s going, you’ll have to figure it out

• In other words, this is part of what you’ll do for the assignment

Page 98: Android 5:   Wari

98

• public void sendMessage(View view) {• Button clickedButton = (Button) view;

• if(clickedButton == findViewById(R.id.button1))• {• TextView cup = (TextView) findViewById(R.id.textView1);• int handFull = Integer.parseInt(cup.getText().toString());

• if(handFull > 0)• {• cup.setText("0");• playNextCup(this, (TextView) findViewById(R.id.textView2), handFull);• }• }• else if(clickedButton == findViewById(R.id.button2))• {• TextView cup = (TextView) findViewById(R.id.textView2);• int handFull = Integer.parseInt(cup.getText().toString());

• if(handFull > 0)• {• cup.setText("0");• playNextCup(this, (TextView) findViewById(R.id.textView3), handFull);• }• }• …

Page 99: Android 5:   Wari

99

• There is one last thing to mention because it’s a segue into an important aspect of the playNextCup() method, which will be the next topic

• Note the calls to findViewById()• This has come up before, but it bears

repeating:• These calls are floating in space

Page 100: Android 5:   Wari

100

• When the app runs, an instance of the MainActivity class is what’s running on the Dalvik Virtual Machine

• The calls on the implicit parameter are on this activity, the MainActivity

• This is relevant to playNextCup() and the concept is important overall and will be discussed in greater depth in the future

Page 101: Android 5:   Wari

101

playNextCup() for Wari

• playNextCup() is the method that’s called if a player clicks a cup that is not empty

• It is a recursive method that jumps to the next cup in line

• Each successive recursive call jumps to the succeeding cup on the board

• Seeds continue being dropped in each cup until handFull is empty

• This is the condition that ends the recursion

Page 102: Android 5:   Wari

102

• playNextCup() is redundant, like sendMessage()• Just like in sendMessage(), it’s necessary to

know which cup is being played• Which is the next cup is determined by which is

the current cup• Since the cups are found by their id, there has

to be a separate case for each of the 12 cups on the board

Page 103: Android 5:   Wari

103

• Again, the fact that the code is redundant actually makes it relatively easy to write

• Figure out one of the cases• Then copy and paste and change the numbers

identifying the cups

Page 104: Android 5:   Wari

104

• The code for this method does have an additional characteristic that needs to be brought out

• It’s already evident in the signature line, which is shown here:

• public static void playNextCup(Activity activityIn, TextView cupIn, int handFullIn)

Page 105: Android 5:   Wari

105

• Not only does the logic of play and recursion require that the cup and handFull be passed in

• The first parameter passed to the method is an activity• If you go back to sendMessage(), the calls look like this, for

example:

• playNextCup(this, (TextView) findViewById(R.id.textView3), handFull);

• The activity that is passed in is the MainActivity

Page 106: Android 5:   Wari

106

• Passing in this parameter supports calls like these in the body of the method:

• activityIn.findViewById(R.id.textView1)

• findViewById() is called on the activity• findViewById() was also called on the activity in

sendMessage(), but it was a call floating in space• It wasn’t necessary to make the call on “this”

Page 107: Android 5:   Wari

107

• In playNextCup() you will get a compiler error if you don’t pass in the activity so you can call findViewById() on it

• This is the message:• “Cannot make a static reference to the non-

static findViewById(int) from the type Activity”

Page 108: Android 5:   Wari

108

• This error message is more helpful than the ones previously looked at

• playNextCup() is a recursive method which is declared static

• The error message is telling you that in a static method there is no “this”, there is no object, which findViewById() can be called on

• Therefore, in order to make the implementation work, you have to pass in MainActivity when making the call to playNextCup()

Page 109: Android 5:   Wari

109

• The first two if cases for the playNextCup() method are shown on the following overheads

• The full method just continues the pattern• If you need more knowledge in order to

understand what’s going, you’ll have to figure it out

• In other words, this is just like sendMessage()• Doing this is part of what you’ll do for the

assignment

Page 110: Android 5:   Wari

110

• public static void playNextCup(Activity activityIn, TextView cupIn, int handFullIn)

• {• handFullIn--;

• if(cupIn == activityIn.findViewById(R.id.textView1))• {• TextView nextCup = (TextView) activityIn.findViewById(R.id.textView2);• int seedCount = Integer.parseInt(cupIn.getText().toString());• seedCount++;• cupIn.setText(seedCount + "");• if(handFullIn != 0)• {• playNextCup(activityIn, nextCup, handFullIn);• }• else if(seedCount == 2 || seedCount == 3)• {• TextView capturedCup = (TextView)

activityIn.findViewById(R.id.textView14);• int capturedCount =

Integer.parseInt(capturedCup.getText().toString());• capturedCount += seedCount;• capturedCup.setText(capturedCount + "");• }• }

Page 111: Android 5:   Wari

111

• else if(cupIn == activityIn.findViewById(R.id.textView2))• {• TextView nextCup = (TextView)

activityIn.findViewById(R.id.textView3);• int seedCount = Integer.parseInt(cupIn.getText().toString());• seedCount++;• cupIn.setText(seedCount + "");• if(handFullIn != 0)• {• playNextCup(activityIn, nextCup, handFullIn);• }• else if(seedCount == 2 || seedCount == 3)• {• TextView capturedCup = (TextView)

activityIn.findViewById(R.id.textView14);• int capturedCount =

Integer.parseInt(capturedCup.getText().toString());• capturedCount += seedCount;• capturedCup.setText(capturedCount + "");• }• }• …

Page 112: Android 5:   Wari

112

Summary and Assignment

• The summary is simple: Can you do this?• The assignment is equally simple: Do this.• Implement Wari or Togiz Kumalak• You get to choose the number of cups per side

and the initial number of seeds per cup, as long they are >= 6 and 4, respectively

Page 113: Android 5:   Wari

113

• You will turn this in by demonstrating your app to me on your tablet or whatever Android device you’ve decided to develop on

• You can come to my office to do this• You can do it any time on or before the due date• I’m begging you, please, don’t push this beyond

the due date• I make this humble entreaty because it’s for your

own good…

Page 114: Android 5:   Wari

114

The End