




















































In this article, we will start writing our very own Java code at the same time as we begin understanding Java syntax. We will learn how to store, retrieve, and manipulate different types of values stored in the memory. We will also look at making decisions and branching the flow of our code based on the values of this data.
In this order, we will:
(For more resources related to this topic, see here.)
Acquiring the preceding Java skills will enable us to build the next two phases of our math game. This game will be able to ask the player a question on multiplication, check the answer and give feedback based on the answer given, as shown in the following screenshot:
Throughout this book, we will use plain English to discuss some fairly technical things. You will never be asked to read a technical explanation of a Java or Android concept that has not been previously explained in a non-technical way.
Occasionally, I might ask or imply that you accept a simplified explanation in order to offer a fuller explanation at a more appropriate time, like the Java class as a black box; however, never will you need to scurry to Google in order to get your head around a big word or a jargon-filled sentence.
Having said that, the Java and Android communities are full of people who speak in technical terms and to join in and learn from these communities, you need to understand the terms they use. So the approach this book takes is to learn a concept or appreciate an idea using an entirely plain speaking language, but at the same time, it introduces the jargon as part of the learning.
Then, much of the jargon will begin to reveal its usefulness, usually as a way of clarification or keeping the explanation/discussion from becoming longer than it needs to be.
The very term, "Java syntax," could be considered technical or jargon. So what is it? The Java syntax is the way we put together the language elements of Java in order to produce code that works in the Java/Dalvik virtual machine. Syntax should also be as clear as possible to a human reader, not least ourselves when we revisit our programs in the future. The Java syntax is a combination of the words we use and the formation of those words into sentence like structures.
These Java elements or words are many in number, but when taken in small chunks are almost certainly easier to learn than any human-spoken language. The reason for this is that the Java language and its syntax were specifically designed to be as straightforward as possible. We also have Android Studio on our side which will often let us know if we make a mistake and will even sometimes think ahead and prompt us.
I am confident that if you can read, you can learn Java; because learning Java is much easy. What then separates someone who has finished an elementary Java course from an expert programmer? The same things that separate a student of language from a master poet. Mastery of the language comes through practice and further study.
The compiler is what turns our human-readable Java code into another piece of code that can be run in a virtual machine. This is called compiling. The Dalvik virtual machine will run this compiled code when our players tap on our app icon. Besides compiling Java code, the compiler will also check for mistakes. Although we might still have mistakes in our released app, many are stopped discovered at the when our code is compiled.
As you become more advanced in writing Java programs, the solutions you use to create your programs will become longer and more complicated. Java was designed to manage complexity by having us divide our code into separate chunks, very often across multiple files.
Comments are a part of the Java program that do not have any function in the program itself. The compiler ignores them. They serve to help the programmer to document, explain, and clarify their code to make it more understandable to themselves at a later date or to other programmers who might need to use or modify the code.
So, a good piece of code will be liberally sprinkled with lines like this:
//this is a comment explaining what is going on
The preceding comment begins with the two forward slash characters, //. The comment ends at the end of the line. It is known as a single-line comment. So anything on that line is for humans only, whereas anything on the next line (unless it's another comment) needs to be syntactically correct Java code:
//I can write anything I like here
but this line will cause an error
We can use multiple single-line comments:
//Below is an important note
//I am an important note
//We can have as many single line comments like this as we like
Single-line comments are also useful if we want to temporarily disable a line of code. We can put // in front of the code and it will not be included in the program. Recall this code, which tells Android to load our menu UI:
//setContentView(R.layout.activity_main);
In the preceding situation, the menu will not be loaded and the app will have a blank screen when run, as the entire line of code is ignored by the compiler. There is another type of comment in Java—the multiline comment. This is useful for longer comments and also to add things such as copyright information at the top of a code file. Also like the single-line comment, it can be used to temporarily disable code, in this case usually multiple lines.
Everything in between the leading /* signs and the ending */ signs is ignored by the compiler. Here are some examples:
/*
This program was written by a Java expert
You can tell I am good at this because my
code has so many helpful comments in it.
*/
There is no limit to the number of lines in a multiline comment. Which type of comment is best to use will depend upon the situation. In this book, I will always explain every line of code explicitly but you will often find liberally sprinkled comments within the code itself that add further explanation, insight or clarification. So it's always a good idea to read all of the code:
/*
The winning lottery numbers for next Saturday are
9,7,12,34,29,22
But you still want to learn Java? Right?
*/
All the best Java programmers liberally sprinkle their code with comments.
We can think of a variable as a labeled storage box. They are also like a programmer's window to the memory of the Android device, or whatever device we are programming. Variables can store data in memory (the storage box), ready to be recalled or altered when necessary by using the appropriate label.
Computer memory has a highly complex system of addressing that we, fortunately, do not need to interact with in Java. Java variables allow us to make up convenient names for all the data that we want our program to work with; the JVM will handle all the technicalities that interact with the operating system, which in turn, probably through several layers of buck passing, will interact with the hardware.
So we can think of our Android device's memory as a huge warehouse. When we assign names to our variables, they are stored in the warehouse, ready when we need them. When we use our variable's name, the device knows exactly what we are referring to. We can then tell it to do things such as "get box A and add it to box C, delete box B," and so on.
In a game, we will likely have a variable named as something along the lines of score. It would be this score variable using which we manage anything related to the user's score, such as adding to it, subtracting or perhaps just showing it to the player.
Some of the following situations that might arise:
These are fairly arbitrary examples of names for variables and as long as you don't use any of the characters keywords that Java restricts, you can actually call your variables whatever you like. However, in practice, it is best to adopt a naming convention so that your variable names will be consistent. In this book, we will use a loose convention of variable names starting with a lowercase letter. When there is more than one word in the variable's name, the second word will begin with an uppercase letter. This is called "camel casing."
Here are some examples of camel casing:
Before we look at some real Java code with some variables, we need to first look at the types of variables we can create and use.
It is not hard to imagine that even a simple game will probably have quite a few variables. What if the game has a high score table that remembers the names of the top 10 players? Then we might need variables for each player.
And what about the case when a game needs to know if a playable character is dead or alive, or perhaps has any lives/retries left? We might need code that tests for life and then ends the game with a nice blood spurt animation if the playable character is dead.
Another common requirement in a computer program, including games, is the right or wrong calculation: true or false.
To cover almost these and many other types of information you might want to keep track of, every possibility Java has types. There are many types of variables and, we can also invent our own types or use other people's types. But for now, we will look at the built-in Java types. To be fair, they cover just about every situation we are likely to run into for a while. Some examples are the best way to explain this type of stuff.
We have already discussed the hypothetical but highly likely score variable. The sWell score is likely to be a number, so we have to convey this (that the score is a number) to the Java compiler by giving the score an appropriate type. The hypothetical but equally likely playerName will of course, hold the characters that make up the player's name. Jumping ahead a couple of paragraphs, the type that holds a regular number is called an int, and the type that holds name-like data is called a string. And if we try and store a player name, perhaps "Ada Lovelace" in score, which is meant for numbers, we will certainly run into trouble.
The compiler says no! Actually, the error would say this:
As we can see, Java was designed to make it impossible for such errors to make it to a running program. Did you also spot in the previous screenshot that I had forgotten the semicolon at the end of the line? With this compiler identifying our errors, what could possibly go wrong?
Here are the main types in Java. Later, we will see how to start using them:
You might be wondering when you might use numbers of this magnitude. The obvious examples would be math or science applications that do complex calculations but another use might be for timing. When you time how long something takes, the Java Date class uses the number of milliseconds since January 1, 1970. The long data type could be useful to subtract a start time from an end time to determine an elapsed time. float: This is for floating-point numbers, that is, numbers where there is precision beyond the decimal point. As the fractional part of a number takes memory space just as the whole number portion, the range of numbers possible in a float is therefore decreased compared to non-floating-point numbers. So, unless our variable will definitely use the extra precision, float would not be our data type of choice.
I have kept this discussion of data types to a practical level that is useful in the context of this book. If you are interested in how a data type's value is stored and why the limits are what they are, visit the Oracle Java tutorials site at http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html. Note that you do not need any more information than we have already discussed to continue with this book.
As we just learned, each type of data that we might want to store will require a specific amount of memory. So we must let the Java compiler know the type of the variable before we begin to use it.
The preceding variables are known as the primitive types. They use predefined amounts of memory and so, using our storage analogy, fit into predefined sizes of the storage box.
As the "primitive" label suggests, they are not as sophisticated as the reference types.
You might have noticed that we didn't cover the string variable type that we previously used to introduce the concept of variables.
Strings are a special type of variable known as a reference type. They quite simply refer to a place in memory where the storage of the variable begins, but the reference type itself does not define a specific amount of memory. The reason for this is fairly straightforward: we don't always know how much data will need to be stored until the program is actually run.
We can think of strings and other reference types as continually expanding and contracting storage boxes. So won't one of these string reference types bump into another variable eventually? If you think about the devices memory as a huge warehouse full of racks of labeled storage boxes, then you can think of the Dalvik virtual machine as a super-efficient forklift truck driver that puts the different types of storage boxes in the most appropriate place.
And if it becomes necessary, the virtual machine will quickly move stuff around in a fraction of a second to avoid collisions. It will even incinerate unwanted storage boxes when appropriate. This happens at the same time as constantly unloading new storage boxes of all types and placing them in the best place, for that type of variable. Dalvik tends to keep reference variables in a part of the warehouse that is different from the part for the primitive variables.
So strings can be used to store any keyboard character, like a char data type but of almost any length. Anything from a player's name to an entire book can be stored in a single string.
There are a couple more reference types we will explore. Arrays are a way to store lots of variables of the same type, ready for quick and efficient access.
Think of an array as an aisle in our warehouse with all the variables of a certain type lined up in a precise order. Arrays are reference types, so Dalvik keeps these in the same part of the warehouse as strings.
So we know that each type of data that we might want to store will require an amount of memory. Hence, we must let the Java compiler know the type of the variable before we begin to use it.
That's enough of theory. Let's see how we would actually use our variables and types. Remember that each primitive type requires a specific amount of real device memory. This is one of the reasons that the compiler needs to know what type a variable will be of. So we must first declare a variable and its type before we attempt to do anything with it.
To declare a variable of type int with the name score, we would type:
int score;
That's it! Simply state the type, in this case int, then leave a space, and type the name you want to use for this variable. Also note the semicolon on the end of the line as usual to show the compiler that we are done with this line and what follows, if anything, is not part of the declaration.
For almost all the other variable types, declaration would occur in the same way. Here are some examples. The variable names are arbitrary. This is like reserving a labeled storage box in the warehouse:
long millisecondsElapsed;
float gravity;
double accurrateGravity;
boolean isAlive;
char playerInitial;
String playerName;
Here, for each type, we initialize a value to the variable. Think about placing a value inside the storage box, as shown in the following code:
score = 0;
millisecondsElapsed = 1406879842000;//1st Aug 2014 08:57:22
gravity = 1.256;
double accurrateGravity =1.256098;
isAlive = true;
playerInitial = 'C';
playerName = "Charles Babbage";
Notice that the char variable uses single quotes (') around the initialized value while the string uses double quotes (").
We can also combine the declaration and initialization steps. In the following snippet of code, we declare and initialize the same variables as we did previously, but in one step each:
int score = 0;
long millisecondsElapsed = 1406879842000;//1st Aug 2014 08:57:22
float gravity = 1.256;
double accurrateGravity =1.256098;
boolean isAlive = true;
char playerInitial = 'C';
String playerName = "Charles Babbage";
Whether we declare and initialize separately or together is probably dependent upon the specific situation. The important thing is that we must do both:
int a; //The line below attempts to output a to the console Log.i("info", "int a = " + a);
The preceding code would cause the following result:
Compiler Error: Variable a might not have been initialized
There is a significant exception to this rule. Under certain circumstances variables can have default values.
Of course, in almost any program, we are going to need to do something with these values. Here is a list of perhaps the most common Java operators that allow us to manipulate variables. You do not need to memorize them as we will look at every line of code when we use them for the first time:
The formal names for these operators are slightly different from the names used here for explanation. For example, the division operator is actually one of the multiplicative operators. But the preceding names are far more useful for the purpose of learning Java and if you used the term "division operator", while conversing with someone from the Java community, they would know exactly what you mean.
There are actually many more operators than these in Java.
If you are curious about operators there is a complete list of them on the Java website at http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html. All the operators required to complete the projects in this book will be fully explained in this book. The link is provided for the curious among us.
Let's try using some declarations, assignments and operators. When we bundle these elements together into some meaningful syntax, we call it an expression. So let's write a quick app to try some out.
Here we will make a little side project so we can play with everything we have learned so far.
Instead, we will simply write some Java code and examine its effects by outputting the values of variables to the Android console, called LogCat. We will see exactly how this works by building the simple project and examining the code and the console output:
The following is a quick reminder of how to create a new project.
As with all the examples and projects in this book, you can copy or review the code from the download bundle. Just create the project as described previously and paste the code from MainActivity.java file from the download bundle to the MainActivity.java file that was generated when you created the project in Android Studio. Just ensure that the package name is the same as the one you chose when the project was created. However, I strongly recommend going along with the tutorial so that we can learn how to do everything for ourselves.
As this app uses the LogCat console to show its output, you should run this app on the emulator only and not on a real Android device. The app will not harm a real device, but you just won't be able to see anything happening.
//first we declare and initialize a few variables
int a = 10;
String b = "Alan Turing";
boolean c = true;
//Let's look at how Android 'sees' these variables
//by outputting them, one at a time to the console
Log.i("info", "a = " + a);
Log.i("info", "b = " + b);
Log.i("info", "c = " + c);
//Now let's make some changes
a++;
a = a + 10;
b = b + " was smarter than the average bear Booboo";
b = b + a;
c = (1 + 1 == 3);//1 + 1 is definitely 2! So false.
//Now to output them all again
Log.i("info", "a = " + a);
Log.i("info", "b = " + b);
Log.i("info", "c = " + c);
Here is the output, with some of the unnecessary formatting stripped off:
info? a = 10
info? b = Alan Turing
info? c = true
info? a = 21
info? b = Alan Turing was smarter than the average bear Booboo21
info? c = false
Now let's discuss what happened. In step 2, we declared and initialized three variables:
So when we output the values in step 3, it should be no surprise that we get the following:
info? a = 10
info? b = Alan Turing
info? c = true
In step 4, all the fun stuff happens. We add 1 to the value of our int a using the increment operator like this: a++;. Remember that a++ is the same as a = a + 1.
We then add 10 to a. Note we are adding 10 to a after having already added 1. So we get this output for a 10 + 1 + 10 operation:
info? a = 21
Now let's examine our string, b. We appear to be using the addition operator on our eminent scientist. What is happening is what you could probably guess. We are adding together two strings "Alan Turing" and "was smarter than the average bear Booboo." When you add two strings together it is called concatenating and the + symbol doubles as the concatenation operator.
Finally, for our string, we appear to be adding int a to it. This is allowed and the value of a is concatenated to the end of b.
info? b = Alan Turing was smarter than the average bear Booboo21
This does not work the other way round; you cannot add a string to an int. This makes sense as there is no logical answer.
a = a + b
Finally, let's look at the code that changes our Boolean, c, from true to false: c = (1+1=3);. Here, we are assigning to c the value of the expression contained within the brackets. This would be straightforward, but why the double equals (==)? We have jumped ahead of ourselves a little. The double equals sign is another operator called the comparison operator.
So we are really asking, does 1+1 equal 3? Clearly the answer is false. You might ask, "why use == instead of =?" Simply to make it clear to the compiler when we mean to assign and when we mean to compare.
Inadvertently using = instead of == is a very common error.
The assignment operator (=) assigns the value on the right to the value on the left, while the comparison operator (==) compares the values on either side.
The compiler will warn us with an error when we do this but at first glance you might swear the compiler is wrong.
Now let's use everything we know and a bit more to make our Math game project.
Now that we have all that knowledge under our belts, we can use it to improve our math game. First, we will create a new Android activity to be the actual game screen as opposed to the start menu screen. We will then use the UI designer to lay out a simple game screen so that we can use our Java skills with variables, types, declaration, initialization, operators, and expressions to make our math game generate a question for the player. We can then link the start menu and game screens together with a push button.
If you want to save typing and just review the finished project, you can use the code downloaded from the Packt website. If you have any trouble getting any of the code to work, you can review, compare, or copy and paste the code from the already completed code provided in the download bundle.
The completed code is in the following files that correspond to the filenames we will be using in this tutorial:
As usual, I recommend following this tutorial to see how we can create all of the code for ourselves.
We will first need to create a new Java file for the game activity code and a related layout file to hold the game Activity UI.
Simply change the text MainActivity to GameActivity and the error will disappear. Take a moment to see if you can work out what the other minor change is necessary, before I tell you.
Note the Project Explorer where Android Studio puts the two new files it created for us. I have highlighted two folders in the next screenshot. In future, I will simply refer to them as our java code folder or layout files folder.
You might wonder why we didn't simply copy and paste the MainActivity.java file to begin with and saved going through the process of creating a new activity? The reason is that Android Studio does things behind the scenes. Firstly, it makes the layout template for us. It also registers the new Activity for use through a file we will see later, called AndroidManifest.xml. This is necessary for the new activity to be able to work in the first place. All things considered, the way we did it is probably the quickest.
The code at this stage is exactly the same as the code for the home menu screen. We state the package name and import some useful classes provided by Android:
package com.packtpub.mathgamechapter3a.mathgamechapter3a;
import android.app.Activity;
import android.os.Bundle;
We create a new activity, this time called GameActivity:
public class GameActivity extends Activity {
Then we override the onCreate method and use the setContentView method to set our UI design as the contents of the player's screen. Currently, however, this UI is empty:
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
We can now think about the layout of our actual game screen.
As we know, our math game will ask questions and offer the player some multiple choices to choose answers from. There are lots of extra features we could add, such as difficulty levels, high scores, and much more. But for now, let's just stick to asking a simple, predefined question and offering a choice of three predefined possible answers.
Keeping the UI design to the bare minimum suggests a layout. Our target UI will look somewhat like this:
The layout is hopefully self-explanatory, but let's ensure that we are really clear; when we come to building this layout in Android Studio, the section in the mock-up that displays 2 x 2 is the question and will be made up of three text views (both numbers, and the = sign is also a separate view). Finally, the three options for the answer are made up of Button layout elements. We used all of these UI elements, but this time, as we are going to be controlling them using our Java code, there are a few extra things we need to do to them. So let's go through it step by step:
Notice that the value for the id property is textView. It is this id that we will use to interact with our UI from our Java code. So we want to change all the IDs of our TextViews to something useful and easy to remember.
This Large Text will simply hold our equals to sign and there is no plan to ever change it. So we don't need to interact with it in our Java code. We don't even need to concern ourselves with changing the ID or knowing what it is. If this situation changed, we could always come back at a later time and edit its ID.
As before, we have built our UI. This time, however, we have given all the important parts of our UI a unique, useful, and easy to identify ID. As we will see we are now able to communicate with our UI through our Java code.
With our current knowledge of Java, we are not yet able to complete our math game but we can make a significant start. We will look at how we can ask the player a question and offer them some multiple choice answers (one correct and two incorrect).
At this stage, we know enough of Java to declare and initialize some variables that will hold the parts of our question. For example, if we want to ask the times tables question 2 x 2, we could have the following variable initializations to hold the values for each part of the question:
int partA = 2;
int partB = 2;
The preceding code declares and initializes two variables of the int type, each to the value of 2. We use int because we will not be dealing with any decimal fractions. Remember that the variable names are arbitrary and were just chosen because they seemed appropriate. Clearly, any math game worth downloading is going to need to ask more varied and advanced questions than 2 x 2, but it is a start.
Now we know that our math game will offer multiple choices as answers. So, we need a variable for the correct answer and two variables for two incorrect answers. Take a look at these combined declarations and initializations:
int correctAnswer = partA * partB;
int wrongAnswer1 = correctAnswer - 1;
int wrongAnswer2 = correctAnswer + 1;
Note that the initialization of the variables for the wrong answers depends on the value of the correct answer, and the variables for the wrong answers are initialized after initializing the correctAnswer variable.
Now we need to put these values, held in our variables, into the appropriate elements on our UI. The question variables (partA and partB) need to be displayed in our UI elements, textPartA and textPartB, and the answer variables (correctAnswer, wrongAnswer1, and wrongAnswer2) need to be displayed in our UI elements with the following IDs: buttonChoice1, buttonChoice2, and buttonChoice3. We will see how we do this in the next step-by-step tutorial. We will also implement the variable declaration and initialization code that we discussed a moment ago:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//The next line loads our UI design to the screen
setContentView(R.layout.activity_game);
//Here we initialize all our variables
int partA = 9;
int partB = 9;
int correctAnswer = partA * partB;
int wrongAnswer1 = correctAnswer - 1;
int wrongAnswer2 = correctAnswer + 1;
}//onCreate ends here
/*Here we get a working object based on either the button
or TextView class and base as well as link our new objects directly to the appropriate UI elements that we created previously*/
TextView textObjectPartA =
(TextView)findViewById(R.id.textPartA);
TextView textObjectPartB =
(TextView)findViewById(R.id.textPartB);
Button buttonObjectChoice1 =
(Button)findViewById(R.id.buttonChoice1);
Button buttonObjectChoice2 =
(Button)findViewById(R.id.buttonChoice2);
Button buttonObjectChoice3 =
(Button)findViewById(R.id.buttonChoice3);
In the preceding code, if you read the multiline comment, you will see that I used the term object. When we create a variable type based on a class, we call it an object. Once we have an object of a class, we can do anything that that class was designed to do.
//Now we use the setText method of the class on our objects
//to show our variable values on the UI elements.
//Just like when we output to the console in the exercise -
//Expressions in Java, only now we use setText method
//to put the values in our variables onto the actual UI.
textObjectPartA.setText("" + partA);
textObjectPartB.setText("" + partB);
//which button receives which answer, at this stage is arbitrary.
buttonObjectChoice1.setText("" + correctAnswer);
buttonObjectChoice2.setText("" + wrongAnswer1);
buttonObjectChoice3.setText("" + wrongAnswer2);
If you play with the assignment values for partA and partB, you can make them whatever you like and the game adjusts the answers accordingly. Obviously, we shouldn't need to reprogram our game each time we want a new question and we will solve that problem soon. All we need to do now is link the game section we have just made to the start screen menu. We will do that in the next tutorial.
Now lets explore the trickier and newer parts of our code in more detail.
In step 2, we declared and initialized the variables required so far:
//Here we initialize all our variables
int partA = 2;
int partB = 2;
int correctAnswer = partA * partB;
int wrongAnswer1 = correctAnswer - 1;
int wrongAnswer2 = correctAnswer + 1;
Then in step 3, we got a reference to our UI design through our Java code. For the TextViews, it was done like this:
TextView textObjectPartA = (TextView)findViewById(R.id.textPartA);
For each of the buttons, a reference to our UI design was obtained like this:
Button buttonObjectChoice1 =
Button)findViewById(R.id.buttonChoice1);
In step 4, we did something new. We used a the setText method to show the values of our variables on our UI elements (TextView and Button) to the player. Let's break down one line completely to see how it works. Here is the code that shows the correctAnswer variable being displayed on buttonObjectChoice1.
buttonObjectChoice1.setText("" + correctAnswer);
By typing buttonObjectChoice1 and adding a period, as shown in the following line of code, we have access to all the preprogrammed methods of that object's class type that are provided by Android:
The power of Button and the Android API
There are actually lots of methods that we can perform on an object of the Button type. If you are feeling brave, try this to get a feeling of just how much functionality there is in Android.
Type the following code:
buttonObjectChoice1
Be sure to type the period on the end. Android Studio will pop up a list of possible methods to use on this object. Scroll through the list and get a feel of the number and variety of options:
If a mere button can do all of this, think of the possibilities for our games once we have mastered all the classes contained in Android. A collection of classes designed to be used by others is collectively known as an Application Programmers Interface (API). Welcome to the Android API!
In this case, we just want to set the button's text. So, we use setText and concatenate the value stored in our correctAnswer variable to the end of an empty string, like this:
setText("" + correctAnswer);
We do this for each of the UI elements we require to show our variables.
Playing with autocomplete
If you tried the previous tip, The power of Button and the Android API, and explored the methods available for objects of the Button type, you will already have some insight into autocomplete. Note that as you type, Android Studio is constantly making suggestions for what you might like to type next. If you pay attention to this, you can save a lot of time. Simply select the correct code completion statement that is suggested and press Enter. You can even see how much time you saved by selecting Help | Productivity Guide from the menu bar. Here you will see statistics for every aspect of code completion and more. Here are a few entries from mine:
As you can see, if you get used to using shortcuts early on, you can save a lot of time in the long run.
At the moment, if we run the app, we have no way for the player to actually arrive at our new game activity. We want the game activity to run when the player clicks on the Play button on the main MainActivity UI. Here is what we need to do to make that happen:
setContentView(R.layout.activity_main);
Button buttonPlay = (Button)findViewById(R.id.buttonPlay);
buttonPlay.setOnClickListener(this);
Notice how the this keyword is highlighted in red indicating an error. Setting that aside, we need to make a modification to our code now in order to allow the use of an interface that is a special code element that allows us to add a functionality, such as listening for button clicks. Edit the line as follows. When prompted to import another class, click on OK:
public class MainActivity extends Activity {
to
public class MainActivity extends Activity implements View.OnClickListener{
Now we have the entire line underlined in red. This indicates an error but it's 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. The rules of the OnClickListener interface state that we must implement/use one of its methods. Notice that until now, we have optionally overridden/used methods as and when they have suited us. If we wish to use the functionality this interface provides, namely listening for button presses, then we have to add/implement the onClick method.
@Override
public void onClick(View view) {
}
@Override
public void onClick(View view) {
Intent i;
i = new Intent(this, GameActivity.class);
startActivity(i);
}
OK, so that code is a bit of a mouthful to comprehend all at once. See if you can guess what is happening. The clue is in the method named startActivity and the hopefully familiar term, GameActivity. Notice that we are assigning something to i. We will quickly get our app working and then diagnose the code in full.
Our app will now work. This is what the new game screen looks like after pressing Play on the menu screen:
Almost every part of our code has changed a little and we have added a lot to it as well. Let's go over the contents of MainActivity.java and look at it line by line. For context, here it is in full:
package com.packtpub.mathgamechapter3a.mathgamechapter3a;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button buttonPlay =
(Button)findViewById(R.id.buttonPlay);
buttonPlay.setOnClickListener(this);
}
@Override
public void onClick(View view) {
Intent i;
i = new Intent(this, GameActivity.class);
startActivity(i);
}
}
We have seen much of this code before, but let's just go over it a chunk at a time before moving on so that it is absolutely clear. The code works like this:
package com.packtpub.mathgamechapter3a.mathgamechapter3a;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
You would probably remember that this first block of code defines what our package is called and makes available all the Android API stuff we need for Button, TextView, and Activity.
From our MainActivity.java file, we have this:
public class MainActivity extends Activity implements View.OnClickListener{
Our MainActivity declaration with our new bit of code implements View.OnClickListener that gives us the ability to detect button clicks.
Next in our code is this:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
It is at the start of our onCreate method where we first ask the hidden code of onCreate to do its stuff using super.onCreate(savedInstanceState);. Then we set our UI to the screen with setContentView(R.layout.activity_main);.
Next, we get a reference to our button with an ID of buttonPlay:
Button buttonPlay = (Button)findViewById(R.id.buttonPlay);
buttonPlay.setOnClickListener(this);
Finally, our onClick method uses the Intent class to send the player to our GameActivity class and the related UI when the user clicks on the Play button:
@Override
public void onClick(View view) {
Intent i;
i = new Intent(this, GameActivity.class);
startActivity(i);
}
If you run the app, you will notice that we can now click on the Play button and our math game will ask us a question. Of course, we can't answer it yet. Although we have very briefly looked at how to deal with button presses, we need to learn more of Java in order to intelligently react to them. We will also reveal how to write code to handle presses from several buttons. This will be necessary to receive input from our multiple-choice-centric game_activity UI.
We can now summon enough of Java prowess to ask a question but a real math game must obviously do much more than this. We need to capture the player's answer, and we are nearly there with that—we can detect button presses. From there, we need to be able to decide whether their answer is right or wrong. Then, based on this decision, we have to choose an appropriate course of action.
Let's leave the math game aside for now and look at how Java might help us by learning some more fundamentals and syntax of the Java language.
Let's look at some more operators: we can already add (+), take away (-), multiply (*), divide (/), assign (=), increment (++), compare (==), and decrement (--) with operators. Let's introduce some more super-useful operators, and then we will go straight to actually understanding how to use them in Java.
Don't worry about memorizing every operator given here. Glance at them and their explanations. There, we will put some operators to use and they will become much clearer as we see a few examples of what they allow us to do. They are presented here in a list just to make the variety and scope of operators plain from the start. The list will also be more convenient to refer back to when not intermingled with the discussion about implementation that follows it.
All of these operators are virtually useless without a way of properly using them to make real decisions that affect real variables and code. Let's look at how to make decisions in Java.
As we saw, operators serve hardly any purpose on their own but it was probably useful to see just a part of the wide and varied range available to us. Now, when we look at putting the most common operator, ==, to use, we can start to see the powerful yet fine control that operators offer us.
Let's make the previous examples less abstract using the Java if keyword, a few conditional operators, and a small story: in use with some code and a made up military situation that will hopefully make the following examples less abstract.
The captain is dying and, knowing that his remaining subordinates are not very experienced, he decides to write a Java program to convey his last orders after he has died. The troops must hold one side of a bridge while awaiting reinforcements.
The first command the captain wants to make sure his troops understand is this: If they come over the bridge, shoot them.
So how do we simulate this situation in Java? We need a Boolean variable isComingOverBridge. The next bit of code assumes that the isComingOverBridge variable has been declared and initialized.
We can then use it like this:
if(isComingOverBridge){
//Shoot them
}
If the isComingOverBridge Boolean is true, the code inside the opening and closing curly braces will run. If not, the program continues after the if block without running it.
The captain also wants to tell his troops what to do (stay put) if the enemy is not coming over the bridge.
Now we introduce another Java keyword, else. When we want to explicitly do something and the if block does not evaluate to true, we can use else.
For example, to tell the troops to stay put if the enemy is not coming over the bridge, we use else:
if(isComingOverBridge){
//Shoot them
}else{
//Hold position
}
The captain then realized that the problem wasn't as simple as he first thought. What if the enemy comes over the bridge and has more troops? His squad will be overrun. So, he came up with this code (we'll use some variables as well this time):
boolean isComingOverTheBridge;
int enemyTroops;
int friendlyTroops;
//Code that initializes the above variables one way or another
//Now the if
if(isComingOverTheBridge && friendlyTroops > enemyTroops){
//shoot them
}else if(isComingOverTheBridge && friendlyTroops < enemyTroops) {
//blow the bridge
}else{
//Hold position
}
Finally, the captain's last concern was that if the enemy came over the bridge waving the white flag of surrender and were promptly slaughtered, then his men would end up as war criminals. The Java code needed was obvious. Using the wavingWhiteFlag Boolean variable he wrote this test:
if (wavingWhiteFlag){
//Take prisoners
}
But where to put this code was less clear. In the end, the captain opted for the following nested solution and changing the test for wavingWhiteFlag to logical NOT, like this:
if (!wavingWhiteFlag){//not surrendering so check everything else
if(isComingOverTheBridge && friendlyTroops > enemyTroops){
//shoot them
}else if(isComingOverTheBridge && friendlyTroops <
enemyTroops) {
//blow the bridge
}
}else{//this is the else for our first if
//Take prisoners
{
//Holding position
This demonstrates that we can nest if and else statements inside of one another to create even deeper decisions.
We could go on making more and more complicated decisions but what we have seen is more than sufficient as an introduction. Take the time to reread this if anything is unclear. It is also important to point out that very often, there are two or more ways to arrive at the solution. The right way will usually be the way that solves the problem in the clearest and simplest manner.
We have seen the vast and virtually limitless possibilities of combining the Java operators with if and else statements. But sometimes a decision in Java can be better made in other ways.
When we have to make a decision based on a clear list of possibilities that doesn't involve complex combinations, then switch is usually the way to go.
We start a switch decision like this:
switch(argument){
}
In the previous example, an argument could be an expression or a variable. Then within the curly braces, we can make decisions based on the argument with case and break elements:
case x:
//code to for x
break;
case y:
//code for y
break;
You can see that in the previous example, each case states a possible result and each break denotes the end of that case as well as the point at which no further case statements should be evaluated. The first break encountered takes us out of the switch block to proceed with the next line of code.
We can also use default without a value to run some code if none of the case statements evaluate to true, like this:
default://Look no value
//Do something here if no other case statements are true
break;
Supposing we are writing an old-fashioned text adventure game—the kind of game where the player types commands such as "Go East", "Go West", "Take Sword", and so on. In this case, switch could handle that situation like this example code and we could use default to handle the case of the player typing a command that is not specifically handled:
//get input from user in a String variable called command
switch(command){
case "Go East":":
//code to go east
break;
case "Go West":
//code to go west
break;
case "Take sword":
//code to take the sword
break;
//more possible cases
default:
//Sorry I don't understand your command
break;
}
We will use switch so that our onClick method can handle the different multiple-choice buttons of our math game.
Java has even more operators than we have covered here. We have looked at all the operators we are going to need in this book and probably the most used in general. If you want the complete lowdown on operators, take a look at the official Java documentation at http://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html.
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:
As usual, I recommend following this tutorial step by step to see how we can create all of the code for ourselves.
buttonObjectChoice1.setOnClickListener(this);
buttonObjectChoice2.setOnClickListener(this);
buttonObjectChoice3.setOnClickListener(this);
public class GameActivity extends Activity {
Change it to the following line:
public class GameActivity extends Activity implements View.OnClickListener{
@Override
public void onClick(View view) {
}
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;
}
int correctAnswer;
Button buttonObjectChoice1;
Button buttonObjectChoice2;
Button buttonObjectChoice3;
//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);
@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;
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;
case R.id.buttonChoice3:
//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;
}
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.
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 int. 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. 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 setText method without creating an object first. We can do this process when the class and its methods are designed to allow it.
Finally, we break out of the whole switch statement as follows:
break;
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)));
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.
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.
To enable us to do this, we will first learn some more new on Java and syntax.
Further resources on this subject: