Here we will detect the right or wrong answer and provide a pop-up message
to the player. Our Java is getting quite good now, so let's dive in and add these
features. I will explain things as we go and then, as usual, dissect the code thoroughly at the end.
The already completed code is in the download bundle, in the following files that correspond to the filenames we will create/autogenerate in Android Studio
in a moment:
• Chapter3/MathGameChapter3b/java/MainActivity.java • Chapter3/MathGameChapter3b/java/GameActivity.java • Chapter3/MathGameChapter3b/layout/activity_main.xml • Chapter3/MathGameChapter3b/layout/activity_game.xml
As usual, I recommend following this tutorial step by step to see how we can create all of the code for ourselves.
1. Open the GameActivity.java file visible in the editor window.
2. Now we need to add the click detection functionality to our GameActivity, just as we did for our MainActivity. However, we will go a little further
than the last time. So let's do it step by step as if it is totally new. Once again,
we will give the buttons the ability to listen to the user clicking on them. Type this immediately after the last line of code we entered in the onCreate method but before the closing }. This time of course, we need to add some code to listen to three buttons:
buttonObjectChoice1.setOnClickListener(this); buttonObjectChoice2.setOnClickListener(this); buttonObjectChoice3.setOnClickListener(this);
3. Notice how the this keyword is highlighted in red indicating an error.
Again, we need to make a modification to our code in order to allow the use
of an interface, the special code element that allows us to add functionalities such as listening to button clicks. Edit the line as follows. When prompted to import another class, click on OK. Consider this line of code:
public class GameActivity extends Activity {
Change it to the following line:
public class GameActivity extends Activity implements View.OnClickListener{
4. Now we have the entire preceding line underlined in red. This indicates an error but it is where we should be at this point. We mentioned that by adding implements View.OnClickListener, we have implemented an interface. We can think of this like a class that we can use, but with extra rules. One of the rules of the OnClickListener interface is that we must implement one of its methods, as you might remember. Now we will add the onClick method.
5. Type the following code. Notice the opening curly brace, {, and the closing curly brace, }. These denote the start and end of the method. Notice that the
method is empty; it doesn't do anything but an empty method is enough to
comply with the rules of the OnClickListener interface and the red line that indicated an error has gone. Make sure that you type the following code outside the closing curly brace (}) of the onCreate method but inside the closing curly brace of our MainActivity class:
@Override
public void onClick(View view) {
}
6. Notice that we have an empty line between the { and } braces of our onClick method. We can now put some code in here to make the buttons actually do something. Type the following in between { and } of onClick. This is where things get different from our code in MainActivity. We need to differentiate between the three possible buttons that could be pressed. We will do this with the switch statement that we discussed earlier. Look at the case criteria; they should look familiar. Here is the code that uses the switch statements:
switch (view.getId()) {
case R.id.buttonChoice1: //button 1 stuff goes here break;
case R.id.buttonChoice2: //button 2 stuff goes here break;
case R.id.buttonChoice3: //button 3 stuff goes here break;
7. Each case element handles a different button. For each button case, we need to get the value stored in the button that was just pressed and see if it matches our correctAnswer variable. If it does, we must tell the player they got it right, and if not, we must tell them they got it wrong. However, there is still one problem we have to solve. The onClick method is separate from the onCreate method and the Button objects. In fact, all the variables are declared in the onCreate method. If you try typing the code from step 9 now, you will get lots of errors. We need to make all the variables that we need in onClick available in onClick. To do this, we will move their declarations from above the onCreate method to just below the opening { of GameActivity. This means that these variables become variables of the GameActivity class and can be seen anywhere within GameActivity. Declare the following variables like this:
int correctAnswer;
Button buttonObjectChoice1; Button buttonObjectChoice2; Button buttonObjectChoice3;
8. Now change the initialization of these variables within onCreate as follows. The actual parts of code that need to be changed are highlighted. The rest is shown for context:
//Here we initialize all our variables int partA = 9;
int partB = 9;
correctAnswer = partA * partB;
int wrongAnswer1 = correctAnswer - 1; int wrongAnswer2 = correctAnswer + 1;
and TextView textObjectPartA = (TextView)findViewById(R.id.textPartA); TextView textObjectPartB = (TextView)findViewById(R.id.textPartB); buttonObjectChoice1 = (Button)findViewById(R.id.buttonChoice1); buttonObjectChoice2 = (Button)findViewById(R.id.buttonChoice2); buttonObjectChoice3 = (Button)findViewById(R.id.buttonChoice3);
9. Here is the top of our onClick method as well as the first case statement for our onClick method:
@Override
public void onClick(View view) {
//declare a new int to be used in all the cases int answerGiven=0;
switch (view.getId()) { case R.id.buttonChoice1:
//initialize a new int with the value contained in buttonObjectChoice1
//Remember we put it there ourselves previously answerGiven = Integer.parseInt("" + buttonObjectChoice1.getText()); //is it the right answer?
if(answerGiven==correctAnswer) {//yay it's the right answer Toast.makeText(getApplicationContext(), "Well done!", Toast.LENGTH_LONG).show(); }else{//uh oh! Toast.makeText(getApplicationContext(),"Sorry that's wrong", Toast.LENGTH_LONG).show(); }
break;
10. Here are the rest of the case statements that do the same steps as the code in the previous step except handling the last two buttons. Enter the following code after the code entered in the previous step:
case R.id.buttonChoice2:
//same as previous case but using the next button answerGiven = Integer.parseInt("" + buttonObjectChoice2.getText()); if(answerGiven==correctAnswer) { Toast.makeText(getApplicationContext(), "Well done!", Toast.LENGTH_LONG).show(); }else{ Toast.makeText(getApplicationContext(),"Sorry that's wrong", Toast.LENGTH_LONG).show(); }
break;
//same as previous case but using the next button answerGiven = Integer.parseInt("" + buttonObjectChoice3.getText()); if(answerGiven==correctAnswer) { Toast.makeText(getApplicationContext(), "Well done!", Toast.LENGTH_LONG).show(); }else{ Toast.makeText(getApplicationContext(),"Sorry that's wrong", Toast.LENGTH_LONG).show(); }
break; }
11. Run the program, and then we will look at the code carefully, especially that odd-looking Toast thing. Here is what happens when we click on the leftmost button:
This is how we did it: In steps 1 through 6, we set up handling for our multi-choice buttons, including adding the ability to listen to clicks using the onClick method and a switch block to handle decisions depending on the button pressed.
In steps 7 and 8, we had to alter our code to make our variables available in the onClick method. We did this by making them member variables of our GameActivity class.
When we make a variable a member of a class, we call it
a field. We will discuss exactly when a variable should be
a field and when it shouldn't in Chapter 6, OOP – Using Other People's Hard Work.
In steps 9 and 10, we implemented the code that actually does the work in our switch statement in onClick. Let's take a line-by-line look at the code that runs when button1 is pressed.
case R.id.buttonChoice1:
First, the case statement is true when the button with an id of buttonChoice1 is pressed. Then the next line of code to execute is this:
answerGiven = Integer.parseInt(""+ buttonObjectChoice1.getText());
The preceding line gets the value on the button using two methods. First, getText gets the number as a string and then Integer.parseInt converts it to an integer. The value is stored in our answerGiven variable. The following code executes next:
if(answerGiven==correctAnswer) {//yay it's the right answer Toast.makeText(getApplicationContext(), "Well done!", Toast.LENGTH_LONG).show();
}else{//uh oh!
Toast.makeText(getApplicationContext(),"Sorry that's wrong", Toast.LENGTH_LONG).show();
}
The if statement tests to see if the answerGiven variable is the same as
correctAnswer using the == operator. If so, the makeText method of the Toast object is used to display a congratulatory message. If the values of the two variables are not the same, the message displayed is a bit more negative one.
The Toast line of code is possibly the most evil thing we have seen
thus far. It looks exceptionally complicated and it does need a greater knowledge of Java than we have at the moment to understand. All we need to know for now is that we can use the code as it is and just change the message, and it is a great tool to announce something to the player. By the end of Chapter 6, OOP – Using Other People's Hard Work, the code for Toast will be clear. If you really want an explanation now, you can
think of it like this: when we made button objects, we got to use all the button methods. But with Toast, we used the class directly to access its makeText method without creating an object first. We can do this
Finally, we break out of the whole switch statement as follows: break;
Now that we have improved the project as far as we can with what we learned in this chapter, why not test your understanding of everything you've learned so far?
Self-test questions
Q1) What does this code do?
// setContentView(R.layout.activity_main);
Q2) Which of these lines causes an error?
String a = "Hello";
String b = " Vinton Cerf"; int c = 55;
a = a + b c = c + c + 10; a = a + c; c = c + a;
Q3) We talked a lot about operators and how different operators can be used together to build complicated expressions. Expressions, at a glance, can sometimes make the code look complicated. However, when looked at closely, they are not as tough as they seem. Usually, it is just a case of splitting the expressions into smaller pieces to work out what is going on. Here is an expression that is more convoluted than anything else you will ever see in this book. As a challenge, can you work out: what will x be?
int x = 10; int y = 9;
boolean isTrueOrFalse = false;
isTrueOrFalse = (((x <=y)||(x == 10))&&((!isTrueOrFalse) || (isTrueOrFalse)));
Summary
We covered a lot in this chapter. We went from knowing nothing about Java syntax to learning about comments, variables, operators, and decision making.
As with any language, mastery of Java can be achieved by simply practicing, learning, and increasing our vocabulary. At this point, the temptation might be to hold back until mastery of the current Java syntax has been achieved, but the best way is to move on to new syntax at the same time as revisiting what we have already begun to learn.
In the next chapter, we will finally finish our math game by adding random questions of multiple difficulties as well as using more appropriate and random
wrong answers for the multiple choice buttons.