Download presentation
Presentation is loading. Please wait.
1
Android 7: One Button Recursion and Debugging
3
Introduction This set of overheads 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 Android Studio has built-in debugging features, but sometimes the simple ways are the best…
4
7.1 The OneButtonRecursion app
7.2 Unhelpful Error Messages 7.3 Logging Output
5
7.1 The OneButtonRecursion app
6
Screen shots for the one button recursion app are shown on the following overhead
Functionally all that happens when you click the button is counting down to 0 recursively It happens so fast there’s nothing visible on the screen except the result
8
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. A look at R.java, the resources as made available by the system 4. MainActivity.java, the code for the app
9
As you might guess, part of what makes the app interesting is the fact that it includes recursion
It does something so simple that the recursion, although not necessary, is easy to understand Recursion is covered because it will be used in the implementation of Wari in the assignment The recursion introduces the possibility of certain kinds of runtime errors
10
This example also has some things in common with the earlier assignments
It includes syntax for converting between strings and numbers, which can also lead to errors if not done correctly These errors are runtime errors, so they are something else which leads to the topic of debugging in Android
11
activity_main.xml for OneButtonRecursion
The app uses a RelativeLayout It contains a button and a text view The XML code for the layout is given on the following overheads for reference
12
<RelativeLayout xmlns:android="http://schemas. android
xmlns:tools=" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" >
13
<Button style="?android:attr/buttonStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:onClick="sendMessage" />
14
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
15
There were some items in the XML that haven’t come up before
Where did they come from? I used the graphical tools to drag and drop components into the layout
16
The system generated the corresponding XML
Basically, what you’re seeing are some of the parameters that determine the relative position of widgets in a relative layout As always, if you use the graphical layout tools, you can then edit the system generated XML to tailor the layout to the specific app you’re trying to create
17
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
18
<?xml version="1.0" encoding="utf-8"?>
<resources> <string name="app_name">One Button Recursion</string> <string name="action_settings">Settings</string> <string name="button1Contents">Button1</string> <string name="textView1Contents">4</string> </resources>
19
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
20
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;
21
MainActivity.java for OneButtonRecursion, Discussion
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()
22
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
23
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
24
The logic of counting down recursively is relatively simple
The Java implementation that will be shown includes two elements which are not actually necessary to accomplish this task
25
1. It repeatedly gets a handle on the text view and passes this around, even though there is only one text area 2. It includes an if statement to check which button was clicked, even though there is only one button
26
These elements are included here as a preview of the Wari implementation
Wari will have >1 text view and >1 button In that situation it will be necessary to repeatedly get references and pass them around and check which button was clicked
27
Having seen these two elements in the simple example, they will not be an issue in the more complicated example When considering the Wari implementation code it will be possible to focus on additional complexities which it introduces
28
MainActivity.java for OneButtonRecursion, Code
At the top of the main activity the Log class is imported and the TAG string definition is given Notice how the definition of the TAG is similar to the definition of the EXTRA_MESSAGE in the echoing app The Log class will be used for console output when debugging The TAG is just a constant string that will be used when logging output
29
import android.util.Log;
public class MainActivity extends Activity { private static final String TAG = "OneButtonRecursion"; …
30
sendMessage() for OneButtonRecursion
The code for sendMessage() is shown on the following overhead Notice that the calls to findViewById() and playNextCup() are floating in space They are calls on the MainActivity itself
31
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(cup, handFull); } else
32
playNextCup() for OneButtonRecursion
playNextCup() is the recursive method It contains the uses of Log and TAG (because when you’re doing the recursion it’s a likely place to make a mistake…) Using them for debugging will be discussed shortly
33
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
34
7.2 Unhelpful Error Messages
35
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 Android Studio—they’re beyond the scope of this course I’m referring to simply figuring out what was going on
36
Compiler Error Messages
Compiler errors are shown in the bottom window of the development environment The screen shot on the following overhead illustrates: How a bad line of code is highlighted in the editor And how the error messages are shown at the bottom
38
Line Numbers First helpful hint for debugging in Android Studio:
If you right click on the mouse with the pointer near the left hand margin of the editor, you have the option of showing line numbers in the source This can be very helpful It’s illustrated in the screen shots on the following overheads
41
An Example of a Runtime Error
Runtime errors can leave you in a quandary How do you figure out what went wrong? As usual, like with many systems, the error messages might not be very helpful
42
Being able to look the error message up on the Web can be very helpful in trying to figure out what it means Do not be afraid to do this I find that stackoverflow.com is the likeliest place to find correct answers (after potentially sorting through things that don’t apply)
43
An error that caused runtime problems with OneButtonRecursion is presented below
I realized that I would need to be able to log output in order to figure out what was going on
44
Here is the snippet of code that’s in error:
int handFull = Integer.parseInt(cup.getText().toString()); … cup.setText(handFull); The next overhead shows what happens when you try to run it This is not very helpful
46
The error message gives no clue as to why the app stopped
It doesn’t identify the line number in the code where it stopped
47
It turns out that this is the line of code that’s the problem
It assumes that handFull gets converted to a String automatically cup.setText(handFull); This is not the case
48
It is a potentially confusing error
If you look up setText() in the API, there is a version which accepts an integer parameter, where the integer is the id for a resource The value contained in handFull doesn’t agree with any defined resource id value, so the system has a runtime problem
49
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
50
Once you know what’s wrong, in this example the solution is simple
Turn the parameter into a String This is the corrected code: int handFull = Integer.parseInt(cup.getText().toString()); … cup.setText(handFull + “”);
51
Keep in mind that in this snippet of code, problems can also arise in the first line
int handFull = Integer.parseInt(cup.getText().toString()); … cup.setText(handFull + “”); parseInt() will fail if you apply it to a string that can’t be parsed as an integer
52
This motivates the idea that it’s useful to be able to identify the line of code where execution stopped There are multiple places where failure might have occurred You would like to figure out where, so that you can fix the problem
53
7.3 Logging Output
54
The playNext() method contained calls to the static method i() in the Log class which causes the code to generate runtime output i() is not the most descriptive method name It apparently stands for “information” The code with logging is shown on the following overhead
55
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 { } }
56
The screen shot on the following overhead shows the logcat screen open at the bottom of the development environment after OneButtonRecursion has been run The highlighted lines are the output of the program, showing the succession of values generated by the recursion and put out by the call to Log.i()
58
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
59
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);
60
In order to write to LogCat you need to import the Log class
Log contains static methods, like i() These log methods take two strings as parameters, a tag, and the actual output It’s simplest to just define a TAG up front so that every line from a given app is clearly identified in the LogCat
61
Then at strategic places put calls to Log.i() to see what’s happening
Android Studio has fancier debugging tools, but sending output to LogCat is straightforward and doesn’t require learning anything more about Android Studio
62
An Example The following overhead shows a block of code with a parseInt() call As mentioned, if the parameter can’t be parsed, this will fail
63
TextView capturedCup = (TextView) activityIn. findViewById(R. id
TextView capturedCup = (TextView) activityIn.findViewById(R.id.textView16); int capturedCount = Integer.parseInt(capturedCup.getText().toString()); capturedCount += seedCount; capturedCup.setText(capturedCount + "");
64
The runtime error message generated by a failed parseInt() call will not be very helpful
The error message will not tell you which line of code caused the runtime error The code on the overhead following the next one shows how to identify the line where the problem occurred
65
The technique is to simply call Log.i() after every line of code
When the app stops, it will generate the unhelpful runtime error message You can then look in LogCat and see which line of code was the last one to run successfully This is indicated by the last Log.i() statement which generated output
66
/* 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"); */
67
Summary and Mission Getting OneButtonRecursion to work is part of your assignment Admittedly, this is largely a matter of cutting and pasting from the overheads into Android Studio
68
Even though it’s simple, it’s a worthwhile exercise, assuming you pay attention to the code as you go and familiarize yourself with how it works You will turn this in at the same time as the rest of the assignment
69
The End
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.