Android Development in Android Studio With Java
Android Development in Android Studio With Java
1
INTRODUCTION
JAVA BASICS...............................................................................................................................................................38
2|Page
6.4. Adding and Positioning the Button...................................................................................................112
9.8. Running Our App and Sending Custom Coordinates to the Emulator.................................189
10.1. Introduction............................................................................................................................................192
3|Page
INTRODUCTION
Welcome to your guide to Android™ app development!
This book aims to teach the basics of Android app development in Android
Studio using Java programming language. I assume that you don‟t have
any Java® or Android programming experience at the start of this book. I
am going to explain every bit of app development in simple terms. You‟ll
start from scratch and will be able to convert your ideas to your own apps
after completing this book. A single book obviously cannot make you the
best expert on a platform or programming language however you‟ll have a
solid background and hands-on experience on Android app development
with this book.
4|Page
Originally, Android was created by a company called Android Inc. Google
acquired this company in 2005. After then, Google made it opensource and
Android gained a big momentum. Android has the market share of around
85% in 2016 as shown in Figure 1.1 (data source: http://www.idc.com/).
Considering this market share, it is obviously rewarding to invest in
Android app development.
88,00%
86,00%
Market share
84,00%
82,00%
80,00%
78,00%
76,00%
74,00%
2015-Q4 2016-Q1 2016-Q2 2016-Q3
Period
Android has seven major releases each having several minor revisions. In
order to follow these versions easier, developers name them with cookie
names. The popular versions of Android are Kitkat (Android 4.4), Lollipop
(Android 5.1) and Marshmallow (Android 6.0)
(https://www.statista.com/statistics/271774/share-of-android-
platformson-mobile-devices-with-android-os/). Nougat (Android 7.0) is also
gaining popularity. Android becomes more capable as the version goes up.
However, we have to be careful about selecting the version during app
development because not every device uses the latest version. If we develop
an app for the Lollipop, it may not run on a device which has Froyo
installed. Fortunately, Android Studio enables us to select set the
compatibility.
5|Page
Android is utilized not only in smartphones but also in tablets, netbooks,
digital television boxes, handheld game devices and even in single board
computers such as UDOO. Therefore we first need to select the target
device(s) and version(s) before developing an app.
6|Page
Figure 1.3. Operating system layer between the hardware and the app
The obvious advantage of developing apps that run on virtual machines can
then be stated as: “develop once and run on all platforms”. However,
applications running on virtual machines are slower than native
applications.
Figure 1.5. Virtual machine between the app and the operating system
7|Page
Figure 1.6. Creating an intermediate code from the source code –
intermediate code is interpreted by the virtual machine
We‟ll use the standard and official way of developing Android apps: Java
with Android SDK and we‟ll use Android Studio Integrated Development
Environment (IDE) for this job. You don‟t need to know Java to start
following this book because the basics of Java are also explained in
Chapter 4. I’ll not introduce complicated subjects until I‟m sure that you
understand the basics because it is very easy to get lost while learning a
new programming language. You‟ll not be in such a situation with this
book. I’ll try to teach new concepts in the simplest way possible. Please
don‟t forget that learning a programming language is a non-stop process, it
never ends and this book will help you get started easily.
Now, you know the aims and the method of this book. Let‟s continue with
installation of the Android Studio in the next chapter after having a coffee
break.
9|Page
SETTING UP YOUR DEVELOPMENT ENVIRONMENT
We‟ll use Android Studio, which is the official IDE for Android app
development; therefore we need to install it with the required plugins.
When you download and install Android Studio, Android SDK will also be
automatically installed.
11 | P a g e
Figure 2.3. Opening the SDK Manager
Please open the standalone SDK Manager by clicking the link indicated in
Figure 2.4. In the standalone SDK Manager, click on the “Install …
packages” as shown below:
When AVD Manager appears, there won’t be any AVDs created or installed.
Please click on the + Create a Virtual Device button as shown below:
The recommended targets start from Android 5.1. We can Android 7.0 with
Goole APIs (Nougat) as shown in the figure. Then, please click “Next” and
give a name you like to the AVD. I didn’t change the defaults in the next
screen as shown in Figure 2.10. After clicking “Finish”, the AVD is created
and shown in the AVD Manager as in Figure 2.11. You can now try your
Android apps on this AVD, which will accurately mimic the behaviour of a
real Nexus 5 phone.
We can run the AVD by clicking the “Play” button shown inside the square
in Figure 2.11. The virtual device will appear as in Figure 2.12 which you
can use like a real Nexus 5 phone.
14 | P a g e
After installing both the development environment and the emulator, we‟re
now ready to develop our test drive app, Hello World, in the next chapter.
16 | P a g e
TEST DRIVE: THE HELLO WORLD APP
3.1. General Procedure for Developing an App
A good method for testing the installation of a compiler or a development
environment is to try a “Hello World” example. It just displays a text such
as “Hello World” on the screen. OK, I know it is not an app that you’d be
proud of showing to your family or friends but its usefulness stems from
testing whether your programming environment is working properly and to
see if you’re ready to go for real projects. In our very first Android project,
we will develop an app in which the “Hello, World!” text will be shown in the
middle of the device screen. We will test it on the emulator we created
before but if you have access to an Android device, you can test your “Hello
World” app on it too.
I’d like to point out general steps of app development before setting off for
developing our first app:
5. Building the project: this means creating the executable (file that actually
runs on device or the emulator). This is not difficult as it sounds; Android
Studio does the entire job with a single click,
Figure 3.1. Creating a new Android Studio project for our first app
After selecting to create a new project, a dialog box for entering the project
settings will appear as in Figure 3.2. In the first textbox (shown by “1” in
the figure), we are required to enter the project name, which will also be the
name of the app. I entered “Hello World” but you can enter another name
as you wish. The company domain is given in the next textbox shown by
“2”. This is a string similar to a web address that is used to distinguish
among developers in the Google Play market. You can use any unique
domain here. If you won’t upload your app to Google Play (as in this
example where we’re just developing for learning the basics), you can use
18 | P a g e
any domain you like. I used the one shown in the figure. And then, we need
to select the location on the computer to save the project files (shown by
“3”). You can select any place you like to save your project files.
After clicking “Next”, the Target Android Devices window shown in Figure
3.3 will appear. I selected the Phone and Tablet checkbox and then set the
Minimum SDK as API 15 – Android 4.0.3. This means that the app we‟ll
develop will be able to run on devices having Android version 4.0.3 or
higher. After selecting the target, please click “Next”.
19 | P a g e
Figure 3.3. Selecting target devices
The template of the user interface is selected in the following dialog. As you
can see from Figure 3.4, there are several templates including a login
activity, maps activity, etc. However, since our aim is just writing a text on
the screen, it is OK to select the Empty Activity as shown in Figure 3.4. So,
what does an activity mean? Activities can be defined as screens shown
to the user with user interfaces. Therefore, we have to include an activity
to have an app because as you know Android apps are visual programs
that have one or more user interfaces.
After selecting the default activity, Android Studio asks us to give names to
the activity and the related layout file as shown in Figure 3.5. Since we will
have a single activity in this app, it is perfectly OK to leave their names as
defaults. When we click “Finish”, Android Studio will create the project files
and folders automatically (this make take a while) and then the IDE will
appear as in Figure 3.6.
20 | P a g e
Figure 3.4. Adding an activity template to the app
21 | P a g e
Figure 3.6. Basics sections of Android Studio
Section 1. The project files and folders can be viewed from here. In
addition, new files can be added from this pane. We need to double-click on
the filenames here to open them in the middle pane. The project structure
will be explained in detail in the next subsection.
Section 2. The opened files can be activated from the tabs located here for
viewing in the middle pane.
Section 3. This is the middle pane. Contents of the active files can be
viewed and changed from here. For the project shown in Figure 3.6, the file
called “MainActivity.java” is the active tab in Section 2 therefore the middle
pane in Section 3 shows the contents of this “MainActivity.java” file.
Section 4. This section is also controlled via tabs. The developer can switch
project files, structures, captures and favourites for viewing in the left pane.
22 | P a g e
Android Studio. Therefore, the message says that the building engine
completed its previous task in 14 seconds.
Section 6. This is the Run button of Android Studio. When we set up the
user interface and write the Java code of a project, we click this button to
make the Android Studio build the project (which means creating the
executable file from project files) and then we can run it on an emulator or
on a real device.
The default folders (shown inside the rectangles in Figure 3.8) and their
contents are explained as follows:
23 | P a g e
Figure 3.7. Switching among different ways of viewing files and folders
3. res folder: The resource files are contained in this folder. Resources
basically mean all the needed files except the source code. For example, if
we want to include an mp3 file in our project, we place this file inside the
“res” folder.
24 | P a g e
Figure 3.8. Default folder and file structure of an Android project
The media, image and layout files residing in the resources folder are
accessed via Java code written in MainActivity.java as we‟ll see in a while.
25 | P a g e
Figure 3.9. Layout of the activity
As you can see, the layout of the activity is shown in the middle pane. The
name of the app appears at the top of the activity. The default empty
activity contains a default text which is shown inside the circle in the above
figure. At the left top of the middle pane, there exists a tab called “Palette”
indicated inside the rectangle in the figure. When we click on this tab, the
palette shown in Figure 3.10 appears from which we can add all possible
user interface objects and layout templates to the activity.
26 | P a g e
Figure 3.10. The component palette
When the palette tab is clicked, two panes are opened: the Palette shown by
the upper rectangle and the Component Tree pane inside the lower
rectangle in Figure 3.10.
The Palette contains several groups like Widgets, Text Fields and Layouts.
We can easily drag and drop these components to the user interface. On
the other hand, the Component Tree lists the activity’s components in a
hierarchical manner. We‟ll see the utilization of these components as we
develop complex apps in the following chapters. However, our aim for now
is to write a text on the screen. As you can see from Figure 3.10, Android
Studio already placed a “Hello World” text at the top left of the view.
27 | P a g e
Figure 3.11. Drag and drop operation on the TextView
After the drag and drop operation, the TextView will be kept selected. We
can now change the properties of the TextView using the Properties pane
which is at the right of the Layout view as shown inside the rectangle in
Figure 3.12. Please click the arrow shown inside the circle in this figure to
open the basic editable properties of the TextView.
28 | P a g e
Figure 3.12. The Properties pane
The editable properties of the TextView component are shown inside the
rectangle in Figure 3.13. In order to display the “Hello World” text in a
better way, I changed its text size to 24sp (sp = scale–independent pixels)
and its style to bold by clicking the B button in the textStyle section.
We have now completed setting up the user interface. Since we don‟t want
our first app to do something interactive, we don‟t need to write single line
of code for now. Of course we‟ll do a lot of coding in the upcoming projects
but we don‟t need any coding here.
29 | P a g e
Figure 3.13. The editable properties of the TextView
In order to build and run the project, please click the “Run” button as
indicated by the arrow in Figure 3.13. The emulator and device selection
dialog shown in Figure 3.14 will appear. Since we have created a Nexus 5
emulator before, it is automatically selected as shown inside the rectangle.
If we had connected a real Android device via USB cable to the computer, it
would also show up in this dialog. However, since there is no real device
connected for now, the dialog gives a warning at the top shown inside the
ellipse in the figure. Please click “Next” and then the emulator will boot like
a real device. It takes some time depending on your computer speed to
completely start the emulator (something like 20 secs).
When the emulator starts running, you‟ll see a Nexus 5 screen as shown in
Figure 3.15. You can use it like a real device (apart from calling and SMS
features of course), and you can also use the controls on the right bar for
changing general properties of the emulator if you want to.
30 | P a g e
Figure 3.14. Selecting the target for running our first app
The emulator started but we cannot see our app running on it. Don‟t panic!
If we check the main Android Studio window, we can see that it has given a
warning as shown below:
After the building process, the emulator will run our first app as in Figure
3.18. If you see the emulator screen shown in this figure,
congratulations. You’ve successfully created your first Android app.
We can make any change in our app, and then press the “Re-Run” button
indicated by the arrow in Figure 3.19. The emulator will install the updated
app for emulating.
As you can see from your very first project, Android Studio offers vast
number of possibilities and a user–friendly interface for transforming your
ideas into Android apps.
32 | P a g e
Figure 3.17. Android Studio in the process of building our project
I changed the text to “Hello Android!” from the TextView properties pane
(shown in Figure 3.12) and pressed the Re-Run button. Android Studio
33 | P a g e
built the project again and the updated app is displayed on the emulator
screen as below:
You can stop the emulator running the app using the square red “Stop”
button which is just at the right of the “Re-Run” button. When you stop the
app, the emulator will not shut down completely and wait for the next run.
34 | P a g e
After you’ve enabled the Developer Mode, you‟ll find a new section called
“Developer options” under the Settings of your device. Please tap on it and
then check “USB debugging” to enable debugging via the USB connection.
You can now install apps from Android Studio to your device over the usual
USB connection.
Now, we need to make our app “debug gable”. For this, open the
AndroidManifest.xml file by double-clicking on it and add the text
android:debuggable="true"
Code 3.1
35 | P a g e
We are now ready to test our “Hello World” app on the real device. When we
hit the “Run” button in Android Studio, the following device selection
window will appear:
I have connected my Asus Zenfone 6 hence its name is written in the device
selection window; it will obviously be different if the device you connected is
different. After the device selection, click on the “OK” button and then the
app screen of Figure 3.18 should appear on your actual device. If you see
the “Hello World!” text on the real device, it’s excellent. You now know how
to install your apps on real Android devices. Running an app on a real
hardware is sometimes essential because some operations like SMS
sending and calling can only be done on real devices.
We have developed out test drive app, “Hello World”, and learned
37 | P a g e
JAVA BASICS
You – Me too. And also very hungry. Could you please cook a frozen
chicken korma for me? There should be some in the fridge. I‟m sure you‟ll
also have one, I know you love it.
Your partner – Yummy yummy. I’ll darling, it will be sizzling when you
arrive. See you in a while, bye. (A caring wife!)
38 | P a g e
Then, she’ll find the frozen korma wherever it is in the fridge, unpack it,
remove the sleeve and pierce film lid in several places. Set the timer, power
on the microwave (or oven) and cook it. She’ll cook the included pilau rice
too without a need to ask you. That’s it. However, if you had a robot wife
with a computer brain, the dialog would be more like this:
You – Very tired. And also very hungry. Could you please cook a frozen
chicken korma for me? There should be some in the fridge.
Robot wife – Where is the frozen korma in fridge, do you want me to cook
pilau rice too? Do you want them normal or overcooked? Do you want a
garlic bread too? When do you want it to be ready?....
Well, any programmable digital device is more or less the same. We have to
tell exact things to them. We do this by using programming languages.
There are a lot of different programming languages used to develop software
for different platforms. You can check the widely used programming
languages and their rankings at the TIOBE index website:
http://www.tiobe.com/tiobe-index/. It is sometimes difficult to choose
which programming language to use. There is not a universally
excellent/complete programming language; they have strong and weak
sides.
When we check the TIOBE index, we see that Java is consistently the most
widely used programming language for years. There are several reasons for
this. The main reasons are: i) being platform independence, ii) having a lot
of libraries and iii) having object oriented nature, iv) having a strong
39 | P a g e
security and robustness. Because of these reasons, Android apps are also
mainly developed in Java. Therefore, in order to learn Android app
development, we have to grasp the basics of Java programming language.
After learning Java, we‟ll use Android SDK libraries with Java and develop
Android apps.
We‟ll create a new Java file in order to try Java codes. For this, right click
on one of the java folders such as com.example.atomic.javabasics1 in the
above figure (or another Java folder in the project you created, your folder
names will be different because your project name is different) and then
select New Java Class as shown in Figure 4.2.
40 | P a g e
Figure 4.2. Creating a new Java Class
In Java, all programs are classes therefore we create a new Java Class.
(We‟ll learn classes later in this chapter.) Please name the new class
without any spaces and special characters (I named it as JavaBasics) and
then click “OK” as shown below:
It is worth noting that the file kind is class as shown inside the ellipse in
Figure 4.3. After clicking “OK”, Android Studio will create the new Java file
called JavaBasics.java and show it in the middle pane as shown in Figure
4.4.
41 | P a g e
Figure 4.4. The contents of the new Java file
The new Java file has the following default lines of code:
package com.example.atomic.javabasics1;
The first line defines a package that contains our new Java class. Java
classes are organized in packages. Packages are like folders on your
computer that hold several files inside.
The second line is the main class definition. All programs are classes in
Java hence all Java files (programs) should have a class definition for
compilation. Please always remember that the class definition should
match the name of the Java file (in our case the filename is
JavaBasics.java and the class name is JavaBasics).
The contents of the programs are written inside the curly brackets opened
just after the class name definition in the second line and closed in the
third line in Code 4.1.
Our Java file only has basic package and class definitions by default. The
body of the Java class is empty thus this Java program does not do
anything at all when it is compiled and run.
42 | P a g e
The source files of Java programs have .java extension. The Java
compiler generates a .class file from .java file. This .class file is then
executed on a Java Virtual Machine. This flow is shown below:
Anyway, let’s see how we can make a “Hello World” program from our
JavaBasics.java file. In a Java source file, the following code line prints a
text in the terminal window:
Code 4.2
In this code line, System.out means that Java will output something and
println() method outputs the text written inside it. It is worth noting that
texts are written inside double quotation marks (“…”) so that the Java
system knows that the programmer refers to a text. Therefore, by placing
“Hello World” inside the function shown in Code 4.2, we can print “Hello
World” text on the screen in Java using the code below:
System.out.println("Hello World");
Code 4.3
So, where will we place this line in our java file? We learned that the
Java code should be between the curly brackets of the class definition.
Hence, we may try to obtain our Java “Hello World” program by placing
Code 4.3 into Code 4.1 as follows:
package com.example.atomic.javabasics1;
43 | P a g e
System.out.println("Hello World");
}
Code 4.4
If we try to compile and run this code, the compiler gives an error and
doesn’t run our program. It is because all Java programs should have a
main method. The main method indicates the starting point of a Java
program which will be executed firstly when the program is run. Adding
the main function, we obtain a correct “Hello World” program in Java as
follows:
package com.example.atomic.javabasics1;
System.out.println("Hello World");
}
}
Code 4.5
The main function is defined in line 3 above: public static void main(String
args[]) . In general, the main method is not explained at this stage and the
tutors say “just accept the main method as it is for now, we‟ll learn more
about it later”. However, I’d like to point out the general structure of the
main method:
This method has three keywords in the front: public , static and void. Their
meanings can be summarized as follows:
44 | P a g e
3. void: the main method will not return a value.
These will be clearer when we learn classes in the last subsection of this
chapter.
The main method also has arguments which are the inputs to this method
in the form of String args[].These mean that the main method can have
several inputs (arguments) in text form. These will be understood better
when we dive deep on functions and their arguments later.
Please don’t panic and don’t be put off at this point. I know these may
be confusing and you might say “Writing just a Hello World program takes
ages with Java and it is confusing.” Java codes are generally longer
compared to other programming languages. However, this is also a strong
side of Java. This is because Java is a very organized and structured
language that provides the developer with increased number of possibilities
with lower error-prone coding.
After inserting Code 4.5 to our JavaBasics.java file, we are now ready to
run our Java “Hello World” program. For this, find the JavaBasics.java from
your file explorer in Android Studio, right-click on it and then select Run
“JavaBasics.main()” as shown below:
45 | P a g e
Android Studio will compile our JavaBasics.java file and then run it. This
takes a while. After then, the output of the program will be displayed in the
Terminal window at the bottom pane of Android Studio as shown in Figure
4.7.
We have now written, compiled and run our first Java application in
Android Studio without the need of using any other development
environment. Let‟s continue with learning about variables used in Java in
the next subsection.
Just as real world boxes that can be used to hold different things like a
sugar box, a match box or a component box, variables in programming
languages also have different types.
46 | P a g e
1. Primitive variable types: These variable types hold single data at a
time. In other words, primitive variables hold primitive values. Primitive
variables always have values. Primitive variables exist from their creation to
the end of a Java program.
These may seem confusing at first but please just try to remember that
primitive types are used to store actual values but reference types store a
handle to an object.
The widely used variable types used in Java are shown in the following
figure:
Code 4.6
In this code, the word boolean is the keyword used for defining a boolean
variable. The name of the variable to be created is written next to the
keyword. In this example, the variable name is myBoolean . The equal sign (=) is
used to assign a value therefore true is assigned to the newly created
variable in this code. This assignment can be visualised as in Figure 4.9.
On the other hand, Java statements are ended using a semicolon (;) as in
Code 4.5 otherwise the compiler gives an error and doesn’t compile our
program. The template is similar for other variable types too. Boolean
variables are generally utilized for decision making in applications which
uses complex logic.
48 | P a g e
int type variables are used to store integer numbers. For example, the
following code defines an integer and assigns the value of 5 to it during
declaration. In other words, a new int type variable is created and
initialized to 5:
int myInteger = 5;
Code 4.7
As you can see from this code, variables that hold integer numbers are
defined using the keyword int . After defining and initializing an int , we can
perform mathematical operations on it. The following code shows the whole
Java source code where an int type variable is created, initialized and then
another integer value is added to it before printing the result on the
terminal screen:
package com.helloworld.quantum.helloworld;
public class JavaBasics {
public static void main(String args[]){
int myInteger = 5;
myInteger = myInteger + 7;
System.out.print("Sum = " + myInteger);
}
}
Code 4.8
49 | P a g e
Figure 4.10. Addition principle
Please note that, its value will be written next to the expression “Sum = ” in
this code. This Java program and its output are shown in Figure 4.11.
int type variables can store numbers from –2 147 483 648 to +2 147 483
647 (these are not phone numbers!). If the numbers we will use are not
that big, we can use short type variables which have the limits of –32768
to +32767. If you say that you‟ll store numbers for rocket science, you
can use long type variables instead, which have the range of -2 63 to 263–1
(really big numbers). The definition and assignment of int, short and
long types are the same, only the size of the numbers they can hold are
50 | P a g e
different (and of course the memory size they will take proportional to
the number length they store).
Another integer variable type is byte . A byte can store numbers between –
128 to 127. In computers, a byte represents 8 bits (binary digits). 8 bits
can have the values between 8 zeros (00000000) to 8
If we try to assign a number which is not in the range of –128 and 127 to a
byte , the compiler gives an error as shown in Figure 4.12.
51 | P a g e
line and shows a red bulb at the incorrect line(s). If we click on these red
bulbs, the compiler gives recommendations for correcting our expression.
The last but not the least important integer variable type is char . It stores
value between 0 and 65535 which constitutes 16 bits (= 2 bytes). char
Please note that the characters assigned to char variables are written inside
single quotes to tell the Java compiler that this value is of character type.
The terminal output of this code is shown below:
52 | P a g e
Figure 4.13. char definition in Java
types can store 7 fractional digits while this number is 16 for double types.
Two variables are defined in the following code snippet with double and float
types and then they are printed to see what Java can get from their
initializations:
package com.helloworld.quantum.helloworld;
public class JavaBasics2 {
public static void main(String args[]){
float myFloat = 1.12345678901234567890f;
double myDouble = 1.12345678901234567890;
System.out.println("myFloat is: " + myFloat
+ ", myDouble is: " + myDouble);
}
}
Code 4.11
Please note that, the decimal number trying to be assigned to myFloat variable
is written by an f letter at the end in the above code
53 | P a g e
(1.12345678901234567890f). This is because Java tries to take any
compiler that we want to create a float type variable. The output of this code
in Android Studio is shown below:
We have learned primitive types until here which are built into Java
language and store actual values. The second main class of variables are
reference types. Reference types do not store values; instead they store
addresses of the objects they refer. So what is an object? An object is a
conceptual bundle that consists of values and related methods (operations
that can be applied on values).
54 | P a g e
There are several forms of reference types. The two widely used types are
arrays and classes. Arrays are variable types that store multiple values of
the same type in an ordered fashion. A typical array can be illustrated as in
Table 4.1.
Index Value
0 „J‟
1 „a‟
2 „v‟
3 „a‟
Table 4.1. Structure of an array
Arrays have indices and values. The values of the array shown above are of
char type however the value can be of any primitive or reference type as long
as all values are of the same type.
Array elements have indices for accessing, deleting them or changing their
entries. Indices of arrays always start with 0 and increase one by one. We
can use the following code for defining the array shown above:
Code 4.12
We can access each element of this array using the following form:
myArray[index]. We can print the first and the second elements of this
array in the terminal as shown in Figure 4.15.
55 | P a g e
Figure 4.15. Printing elements of a char array The elements of
arrays can be changed separately as follows:
myArray[1] = 'v';
Code 4.13
The second element of myArray is changed from „a‟ to „v‟ by this code.
After this line, the contents of the array are: [„J‟, „v‟, „v‟, „a‟].
Arrays are useful while dealing with series of data of the same type. For
example, if we want to save the data gathered from the acceleration sensor,
we can use an array having float or double type elements.
Another widely used reference type in Java is the String . Strings store
multiple characters. The first letter of String is capitalized because Strings
are in fact objects in Java. The following code creates a String and initializes it
to “Let‟s have a pizza”. Please note that values of Strings are written in double
quotes:
Code 4.14
56 | P a g e
Since Strings are objects, they have related methods for operation on their
values. For example, the method .length() returns the number of characters in
a string as shown below:
Code 4.15
Java output shows that the String “Let‟s have a pizza” has 18 characters. It is
because the spaces in a String are also counted as separate characters.
There are dozens of other methods those can be applied on Strings. We‟ll
utilize them when we develop complete Android apps in the next chapters.
57 | P a g e
Code 4.16
- “If their coffee is tasty I’ll get another one, else I’ll grab a tea”.
58 | P a g e
If–else structure: In this conditional, if the condition is satisfied, the code
inside the if block is executed. If the condition isn’t satisfied, then the code
in the else block is executed. Hence, if we need tell the rainy – not rainy
example using an if–else block, we do it as follows:
if it’s rainy {
} else {
I’ll not take my umbrella.
Let‟s see how we can check if two numbers are equal in Java using an if-
else statement:
package com.helloworld.quantum.helloworld;
public class JavaIfElse {
public static void main(String args[]){
int a = 4;
int b = 4;
if (a == b){
initialized to 4.
In the next line, the if statement checks if a and b are equal.
The comparison operator == is used to check the equality.
If the result of this comparison is true, the statement inside the if block
System.out.println("a and b are equal"); is executed which prints “a
and b are equal” on the terminal screen.
If the result of this comparison is false, the statement inside the if
Since we initialized both a and b to 4, they are equal and the Java compiler
executes the code inside the if block as follows:
When we change one of the numbers to something other than 4, the code
inside the else block is executed as shown in Figure 4.19.
60 | P a g e
Figure 4.19. if–else statement in Java when the condition not satisfied
61 | P a g e
}
}
Code 4.18 (cont’d from the previous page)
}
}
}
Code 4.19 (cont’d from the previous page)
In this example, the grade variable has the type char . This variable is
switched and checked against the characters „A‟, „B‟, „C‟, „D‟, „E‟. The
switched variable is initialized to „B‟ therefore the code block inside the
case „B‟: will be executed. It is worth noting the break; statements in each
case block; break makes the whole switch block to end as it is needed in this
example. Please note the default: block at the end of the program. The code
block inside default is executed when none of the above cases are satisfied. If
we enter a character other than „A‟, „B‟, „C‟, „D‟ and „E‟, the program will
print “Not a valid grade” on the terminal. A default block is not mandatory in
Java but useful as we‟ll see in Android app development chapters.
63 | P a g e
Selecting if–else or switch–case: If the checked variable has a lot of
discrete values, switch–case blocks are easier to use.
There has to be 44 more lines of code in the line shown by dots (shortened
above). As you can see, this simple task would require 51 lines of code
without loops. Moreover, it’s error prone. Please remember that we want to
perform things in programming with shortest code possible to prevent
errors.
There are three types of loops in Java: for loop, while loop and do-while loop.
1. for loop: We use for loops when we know how many times an operation
will be performed. The general structure of a for loop is as follows:
for (type counter = initial value; counter
check; counter increment/decrement
64 | P a g e
statement) {
Code to be performed
repeatedly }
Code 4.21
package com.helloworld.quantum.helloworld;
public class JavaFor {
public static void main(String args[]){ int sum = 0;
for (int counter = 0; counter <=50; counter++){
sum = sum + counter;
}
System.out.println("Sum is " + sum);
}}
Code 4.22
In this code, a variable called sum is created to hold the sum. Then, a for
loop is defined in which an integer variable named counter is created and
looped from 0 to 50. In the for loop, the loop variable counter is incremented
by 1 in each iteration by the expression counter++ . Therefore, the counter variable
takes the values of 0, 1, 2, 3, …, 50 as the loop continues to cycle. When it
takes the value 51, the loop condition counter=<50 , which means equal or lower
65 | P a g e
than 50, is not satisfied therefore the loop ends without performing the loop
operation for counter = 51 .
The variable sum is initialized to 0 and then the counter is added to it in the
loop block by the expression: sum=sum+counter. This method adds the
numbers from 0 to 50 to the sum variable. In the end, the sum variable is
printed on the terminal screen as in Figure 4.21. The sum of the numbers
from 0 to 50 is calculated as 1275.
2. while loop: while loops can be used even when we don‟t know at which
iteration the cycle will end. The main difference of for and while loops is
that the incrementing method of the loop variable is specified inside the
loop therefore it provides a bit more flexibility. The calculation of the sum of
numbers from 0 to 50 using a while loop is shown in Code 4.23.
package com.helloworld.quantum.helloworld;
public class JavaWhile {
public static void main(String args[]){
int sum = 0;
int counter = 0;
while (counter <=50){
sum = sum + counter;
66 | P a g e
counter++;
}
System.out.println("Sum is " + sum);
}
}
Code 4.23
As you can see from above, the loop variable counter is defined before the
while loop. The while loop checks if the condition counter=<50 is satisfied.
When it is satisfied, the expressions inside the while loop are executed,
otherwise the loop ends. The counter variable is incremented inside the while
loop by the expression counter++ . The output is again 1275 as shown in Figure
4.22.
3. do–while loop: do–while performs similar to the while loop except the
loop variable is checked at the end of the loop block as follows:
package
com.example.atomic.javabasics1; public
class JavaDoWhile {
public static void main(String args[])
{
67 | P a g e
int sum = 0;
int counter = 0;
do {
sum = sum +
counter; counter++;
}
while (counter<=50);
// do-while loop ends here
System.out.println("The sum is " +
sum);
}
}
Code 4.24
The sum is again calculated as 1275 in this code. As we can see from above
code, while and do–while are very similar. On the other hand, please note
the code //do-while loop ends here. This is a comment line in Java. The
compiler ignores anything written next to . Comments are used for
//
68 | P a g e
Figure 4.23. do–while loop example in Java
Note: There are two important keywords that are used to further control
loops: break and continue statements.
These commands are usually used together with an if statement. The break
command breaks the loop; it means the program quits the current loop
before the loop condition expires. On the other hand, continue command
makes the loop continue with the next iteration
Because of this, methods are always defined inside classes. The general
form of a function is as in Code 4.24.
(public) (void) (return type) methodName
(arguments){
......... (code inside the
method)
69 | P a g e
(return output_values;)
}
Code 4.25
Let‟s write a method that adds two integers and prints the sum on the
terminal:
static void addNumbers(int a,
int b){ int sum; sum = a + b;
System.out.println("The sum is " +
sum); }
Code 4.26
In this method:
The static keyword is used that means this method can be called without
creating an object of its class.
void keyword is used because the method won’t output any values; it will
just print on the terminal screen.
Inputs (arguments) of the method has two input variables a and b which
both are of the int type.
70 | P a g e
The sum is calculated inside the function and assigned to the sum
variable. Please note that the variables which are defined inside the
function cannot be accessed outside the function.
Finally, the sum is printed on the terminal screen with the usual
System.out.println() method.
addNumbers(2, 5);
Code 4.27
When we call this method, the input arguments are 2 and 5. The method
will add these numbers and print the result on the screen. The complete
code of the method definition and its call is as follows:
package
com.example.atomic.javabasics1;
public class JavaMethodAdd1 {
71 | P a g e
When we run this program in Android Studio, we get the terminal output
shown in Figure 4.24.
This function didn’t have return values. Let‟s modify it so that the sum of
the input values will be given as a return value. We can do this
modification by just adding the following line instead of the
System.out.println():
return sum;
Code 4.29
We also have to replace the void keyword to int keyword as shown in Code
4.29 because the function will output an int type variable (sum).
When we run the code above, nothing happens because we removed the
printing code from the method and it only outputs the sum. We can print
the output of the method as follows:
package com.example.atomic.javabasics1;
public class JavaMethodAdd2 {
73 | P a g e
Figure 4.25. Using a method that returns a value
Methods are also important to share code among developers. If we can find
a ready-coded method on the Internet, we can utilize it in our apps easily.
Methods are always parts of classes. So, let’s now focus on classes, objects
and inheritance that are the backbones of the so-called “objectoriented
programming”.
74 | P a g e
classes to execute the required computational steps. So, what are classes
and objects?
Let‟s declare a Car class in Java first and then define different car objects
derived from this class as in Code 4.31. In this code, a class named Car is
defined by public static class Car which has variables named colour,
fuel_type and engine_capacity. These are the variables which will be
different for each object derived from this class.
75 | P a g e
Figure 4.26. Class–object relationship by example
package com.helloworld.quantum.helloworld;
public class JavaClassMain1 {
public static class Car {
static String colour;
static String fuel_type;
static float engine_capacity;
public Car(String carColour, String carFuelType,
float CarEngineCapacity){
colour=carColour;
fuel_type=carFuelType;
engine_capacity = CarEngineCapacity;
}
}
public static void main(String args[]){
Car myCar = new Car("Red", "Diesel", 1.2f);
System.out.println(myCar.colour);
}
}
Code 4.32
colour=carColour; fuel_type=carFuelType;
76 | P a g e
engine_capacity = CarEngineCapacity;
Code 4.33
Finally, inside the main function of the program, a Car object called myCar
is created with the line:
Please note that the new keyword is used for creating an object using a
class. We can read this object declaration line as “An object named myCar
is created using the Car class with the parameters of “Red”, “Diesel” and
“1.2f” ”.
Once the object is created, we access its variables and methods using a dot
operator (.). In the last code line of Code 4.31, the colour variable of myCar
object is extracted by the expression myCar.colour and then printed on
the terminal. The output is the colour variable of the myCar object as
shown in Figure 4.27.
We can define any number of different objects using our class like:
We can add a method to the class with the usual method definition. For
example, let’s add a method to display the fuel type as shown in Code
4.35.
77 | P a g e
Figure 4.27. Class and object example in Java
package com.helloworld.quantum.helloworld;
public class JavaClassMain1 {
public static class Car {
static String colour;
static String fuel_type;
static float engine_capacity;
public Car(String carColour, String carFuelType,
float CarEngineCapacity){
colour=carColour;
fuel_type=carFuelType;
engine_capacity = CarEngineCapacity;
}
public void askFuelType(){
System.out.println(fuel_type); } }
public static void main(String args[]){
Car myCar = new Car("Red", "Diesel", 1.2f);
myCar.askFuelType();
78 | P a g e
}
}
Code 4.36 (cont’d from the previous page)
myCar.askFuelType();
Code 4.37
The basic class and object relation can be summarized as in the above code
samples. However, there’s another important property of classes which is
another advantage of object-oriented programming: inheritance.
Inheritance is basically the ability of creating an extended new class (let’s
call this as class2) from an existing class (class 1). The child class (class2) will
79 | P a g e
have the fields and methods of its parent class (class 1). The child class may
also have new variables and methods too.
We have defined a Car class in Code 4.36. Let‟s define a child class called
sedanCar that will extend the parent class Car :
In the first line of this code, the new (child) class sedanCar extends the Car
class. Then, a new integer type variable b_Vol is declared in the new class.
Next, a constructor method for the sedanCar is defined by
public sedanCar(String carColour, String carFuelType, float CarEngineCapacity, int
In Java, the super keyword is used to invoke the constructors of the parent
class in a child class. Therefore, the child class sedanCar inherits the fields
(variables for this case) of the parent class using the super keyword.
The complete code of parent and child classes is given in Code 4.40.
package com.helloworld.quantum.helloworld;
public class JavaClassMain1 {
80 | P a g e
public static class Car {
static String colour;
static String fuel_type;
static float engine_capacity;
public Car(String carColour, String carFuelType, float
CarEngineCapacity){
colour=carColour;
fuel_type=carFuelType;
engine_capacity = CarEngineCapacity;
}
public void askFuelType(){
System.out.println(fuel_type);
}
}
public static class sedanCar extends Car{
int b_Vol;
public sedanCar(String carColour, String
carFuelType, float CarEngineCapacity, int
baggageVol) {
super(carColour,
carFuelType, CarEngineCapacity);
b_Vol = baggageVol;
}
}
public static void main(String args[]){
sedanCar newCar = new sedanCar("Red",
"Diesel", 1.2f, 40);
newCar.askFuelType();
System.out.println(newCar.b_Vol);
81 | P a g e
}
}
Code 4.40 (cont’d from the previous page)
We can apply the method askFuelType on the object newCar derived from the child
class despite the child class doesn’t have askFuelType method explicitly. This is
because the child class inherits all methods of its parent class therefore
sedanCar class actually has the askFuelType method.
In the last line, the b_Vol variable that is unique to the child class is accessed
as usual. The output of this code in Android Studio is shown in Figure
4.29.
If the classes and objects make you confused, don‟t worry. You‟ll
understand them better when we use them for developing Android apps.
Java is, of course, a very extensive programming language and Java SDK
has thousands of methods for developing sophisticated Java programs.
However, I think this much of Java basics lecture is enough for starting to
develop Android apps. I‟m sure you‟ll get used to writing Java code in the
upcoming chapters.
Our aim is to develop an Android app where the background colour of the
app is varied as in a red/blue strobe light. The background colour of the
app will change from red to blue or vice versa each time we click a button
located in the middle of the screen. This is a very simple app but will teach
the basics steps of visual programming.
83 | P a g e
Figure 5.1. Creating a new project in Android Studio
I named the app as “Lighthead app” as shown in Figure 5.2, but you can
give any name you’d like to.
Then, I selected the app to be compatible with phones and tablets having
Android 4.0.3 (Ice Cream Sandwich) or later:
84 | P a g e
Figure 5.3. Selecting app compatibility
We‟ll have a simple screen therefore “Empty Activity” does the job in the
next dialog:
Finally, leave the name of the activity as “MainActivity” and then click
“Finish” to create the project files:
85 | P a g e
Figure 5.5. Final settings
After the project is successfully created, the default view of the Android
Studio will appear in which the middle pane will show the
“MainActivity.java” file as shown below:
86 | P a g e
When the activity_main.xml file is opened, the layout it contains will be
shown in the middle pane as shown in Figure 5.8. This file and other xml
files contain the layout information of an Android app in Android Studio. In
fact, xml files are not only used in Android app development but also in
other areas of computing. xml files are good to express the relations among
different entities in a hierarchical way therefore is a good choice to use in
layout design. xml files are text files but Android Studio interprets them as
layouts as long as they are in the correct format. We can also view the text
file representation of activity_main.xml in Android Studio by selecting the
Text tab as indicated by the arrow in Figure 5.8.
87 | P a g e
Figure 5.8. Viewing activity_main in Android Studio
When the Text tab is selected, the text format of the activity_main.xml file is
displayed in the middle pane as follows:
You don‟t need to be confused about the contents of this file. We‟ll do most
of the layout operations visually. We‟ll only use this text representation in
special cases. However, it is a good practice to follow the contents of the
xml file as we design app layouts. In the above figure, we can see that our
layout consists of a RelativeLayout structure, which begins by the line
<RelativeLayout… and ends with
</RelativeLayout>. Inside this layout, we have a TextView component. In
other words, a TextView component exists inside the RelativeLayout
component. Let‟s now see how an Android app GUI is built in general using
these components.
88 | P a g e
Figure 5.10. Basic hierarchy of the GUI components
The components of the GUI of an Android app have the following basic
properties:
Because all GUI objects are derived from the View class, these GUI
objects are also called as views in Android programming.
ViewGroup’s child classes RelativeLayout, LinearLayout,
AbsoluteLayout and GridLayout are special views that can contain
other views and components. These are used for shaping the layout as
you wish.
An Android GUI should consist of at least one layout class. For example,
our activity_main.xml file has the RelativeLayout as shown in Figure
5.9.
We can build any GUI by using the subclasses of the View class shown
in Figure 5.10.
89 | P a g e
We‟ll see several GUI designs during our app development journey.
Different developers prefer different strategies for shaping their app’s GUI.
In my personal opinion, RelativeLayout provides more flexibility therefore
easier to use. The basic property of the RelativeLayout is that each GUI
object is positioned relative to each other.
Anyway, let’s continue developing our red/blue strobe light app. Please
switch to the Design view of the activity_main.xml file as in Figure 5.8 so
that we can design the GUI visually.
First of all, please delete the default “Hello World” TextView by rightclicking
on it and selecting “Delete” as shown below:
After deleting the default TextView, please find the Button widget from the
objects palette and then drag and drop it in the middle of the GUI by the
help of the guiding lines as shown in Figure 5.12.
90 | P a g e
Figure 5.12. Adding a button widget in the middle of the user interface
When we add a widget to the GUI, it keeps being selected and then its
properties can be viewed from the right pane as shown in Figure 5.13. The
basic properties of the button are shown in this pane. However, we can see
the full list of properties by clicking on the View all properties (can be seen
after scrolling down) as shown in Figure 5.14.
Anyway, let‟s go on with the basic properties pane shown inside the
rectangle in Figure 5.13. In this pane, one of the most important properties
for accessing the button is the ID. All objects of the GUI of an Android app
are accessed through their IDs in the coding part.
91 | P a g e
Figure 5.13. Basic properties of the button widget
In our app, the default ID of the button widget is set as button by Android
Studio. We can change it just by clicking the ID box and replacing the
button text.
The next two boxes refer to the layout width and layout height properties
of the button widget. Their settings determine the width and the height of
the button object in the GUI. They are set as wrap_content by default. This
means that the width and the height of the button will be adjusted to wrap
(cover) the text written inside the button (i.e. button’s label). The other
92 | P a g e
available choice for these parameters is the match_parent as shown in
Figure 5.15. If this is selected, the respective property (width or height) will
be equal to the width or height of its parent container (which is the
RelativeLayout covering the whole screen in this example).
layout_height parameters
Since we don‟t want the button to have a width or height filling the whole
GUI, we need to leave these parameters having the value of wrap_content.
In our app, the button is supposed to change the background colour of the
screen therefore it is good to change the label of the button accordingly.
The button’s label (the text on the button) is Button by default. Let‟s
change it to “Change!” as shown in Figure 5.16.
93 | P a g e
5.3. Writing the Main Code of the App
Since we don‟t need any other widget in the GUI, we can now continue to
programming the app. We will do the programming in the
MainActivity.java file. In order to open this file, navigate to the project
explorer in Android Studio and then double-click on the MainActivity
located under java com…..lightheadapp as shown below:
94 | P a g e
Figure 5.19. The default MainActivity.java file after opening the hidden
lines
The first line is the package definition as in usual Java code. It shows to
which package this file belongs to.
The next two lines are import lines which import the required libraries. In
our file, the AppCompatActivity and Bundle libraries are imported.
They contain the base methods for user interaction and passing data
among different activities.
The next line declares the MainActivity class which extends the
AppCompatActivity class. This is like the class definition in Java. As in Java,
the class name in Android should match the name of the .java file. In
this case, the file is MainActivity.java therefore the name of the class is
MainActivity .
Then an @override command is placed by default. It is used to tell the
compiler that the current class will override any existing superclasses.
The sixth code line defines a method called onCreate() . All activities are
started by a sequence of method calls. onCreate() method is the first of these
calls.
95 | P a g e
The next line, super.onCreate(savedInstanceState); , tells that our code will be
executed in addition to the existing code (if any) of the parent class.
In the last line, setContentView() method sets the activity content from
a layout source. We have set up our app’s layout in the file activity_main.xml .
Android accesses all resources via an auxiliary class called “R”. The R
As you can see from the figure above, an activity may have several phases.
These phases depend on the activity itself as well as the Android operating
96 | P a g e
system. For example, if another activity needs a lot of memory, the current
activity may be paused (onPause()) because Android gives precedence to the
other activity.
In the MainActivity.java file of our app, the onCreate() method is called when
the activity is first created. All static set up are done inside this method.
If we run our app at this stage, we should see the layout we designed. We
can run it in the simulator by hitting the “Run” button and selecting an
emulator as we did in Chapter 3. The Nexus 4 emulator running our app is
shown in Figure 5.21.
97 | P a g e
In order to check the button continuously, the app needs to “listen” the
button. Therefore, we need to create a button listener method and call it
when the activity first starts. We can give any name to out button listener
method such as myButtonListenerMethod(). In this method, we need to
find the button widget using the mentioned R class and create a button
object to access the button. I know this may seem a bit confusing for now
but I‟m sure you‟ll get used to it soon. These are shown in Code 5.1.
We can now access the button using the button object that is created by
line Button button=(Button) findViewById(R.id.button). findViewById() method
finds the views (widgets, layouts, etc.) using their IDs. Remember that we
have given the ID “button” to our button widget during the layout design.
Hence, we accessed it using the R class as R.id.button .
All code lines that will be run when the button is clicked will go inside the
onClick(View v) method.
Our aim is to change the background colour from red to blue and vice versa
as the button is clicked. In the activity_main.xml file, we saw that our GUI
has a RelativeLayout element as the main layout that fills the screen.
Because of this, we can access the background using the following code:
We now need to check the colour of the bgElement . This is because we will
change its colour according to its current colour. If it is red now, the button
will change it to blue. If it is blue now, the button click will turn it to red.
99 | P a g e
int color = ((ColorDrawable) bgElement.getBackground()).getColor();
Code 5.4
In this code, the colour of the background of the layout of the app is taken
by bgElement.getBackground()).getColor(); and then converted to the type
ColorDrawable, which expresses the colour as an integer. Then, this
integer value is assigned to the color variable. In short, the colour of the
background will be expressed in the variable named colour as an integer.
We will now utilize a decision making statement to change the colour such
as:
If the colour is red, change to blue; else (= if the colour is blue) change to
red.
There’s a special class called Color in Android SDK for doing colour related
operations. The expressions Color.RED and Color.BLUE represent the integer values
corresponding to the red and blue colors, respectively. Therefore, the color
variable, which contains the integers corresponding to the background
colour, will be compared to the integer value of red by the expression color
== Color.RED. If they are equal, this means that the background is
currently red and will be changed to blue when the button is clicked. Else,
100 | P a g e
the background is currently blue and will be changed to red when the user
clicks the button.
Combining all these code lines, we reach the button listener method shown
in Code 5.6.
public void myButtonListenerMethod() {
button = (Button)
findViewById(R.id.button);
button.setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
RelativeLayout bgElement = (RelativeLayout)
findViewById(R.id.activity_main);
int color = ((ColorDrawable)
bgElement.getBackground()).getColor();
if (color == Color.RED) {
bgElement.setBackgroundColor(Color.BLUE);
} else {
bgElement.setBackgroundColor(Color.RED);
}
}
});
}
Code 5.6 (cont'd from the previous page)
Please note that we could use the if–else statement without curly brackets
since there are only one line codes inside their blocks. However, I have
written them with brackets for the sake of completeness.
We now have to call this button listener method when the activity is first
created. Therefore, we have to call it inside the onCreate() method as follows:
101 | P a g e
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButtonListenerMethod(); }
Code 5.7
In this code, the background is accessed and then set as red at the start of
the app. Please note that we need to define a separate bgElement object inside
the onCreate() method; we can’t use the bgElement defined inside the
button listener method. This is because all variables and objects declared
in a method are valid only inside that method (also called as scope of
variables).
102 | P a g e
Button button;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout bgElement = (RelativeLayout)
findViewById(R.id.activity_main);
bgElement.setBackgroundColor(Color.WHITE);
myButtonListenerMethod();
}
public void myButtonListenerMethod() {
button = (Button)findViewById(R.id.button);
button.setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
RelativeLayout bgElement =
(RelativeLayout)findViewById(R.id.activity_main);
int color = ((ColorDrawable)
bgElement.getBackground()).getColor();
if (color == Color.RED) {
bgElement.setBackgroundColor(Color.BLUE);
} else {
bgElement.setBackgroundColor(Color.RED);
}
}
});
}
}
103 | P a g e
Code 5.9
Figure 5.22. The app when it is launched (colour and full resolution figure
at the book’s companion website: www.android-java.website)
104 | P a g e
Small exercise: Could you modify the code to change the label of the
button according to the background colour dynamically? If the
background colour will be changed to blue, the button text will read
Convert to blue! otherwise Convert to red!
Figure 5.23. Our app’s screen after subsequent button clicks (colour and
full resolution figure at the book’s companion website: www.android-
java.website)
105 | P a g e
ANDRIOD APP#2: BODY MASS INDEX (BMI) CALCULATOR
After the calculation of the BMI, the following table is the used for assessing
the weight category:
Weight from BMI to BMI
category
Very severely
0 15
underweight
Severely
15 16
underweight
Underweight 16 18.5
Normal
(healthy 18.5 25
weight)
Overweight 25 30
Obese Class I
(Moderately 30 35
obese)
Obese Class II
(Severely 35 40
obese)
Obese Class
III (Very 40 ∞
severely obese)
Table 6.1. BMI categories
(source: https://en.wikipedia.org/wiki/Body_mass_index)
106 | P a g e
In this chapter, we‟ll develop a BMI calculator app and learn to read user
inputs, make calculations inside our code and display results to the user.
107 | P a g e
We‟ll take height and weight inputs from the user and show the BMI result
as a number and its category. We‟ll need to place four TextViews which will
show Enter your weight (kg): , Enter your height (m): , Your BMI: and
BMI category. Please find the widget TextView from the Palette and drag
and drop four TextViews as shown in Figure 6.3.
Figure 6.1. Setting the basic properties of the TextView (You can download
full resolution colour images from the book’s website)
108 | P a g e
Figure 6.3. Placing four TextViews
Once the first TextView is placed, the next one is positioned relative to the
previous one. For out BMI Calculator app, the exact positions are not strict
and I am not giving the exact positions here in order to confuse you. You
can download the project files from the book’s companion website if you’d
like to see which positions I exactly used but it is not mandatory of course.
However, we need to leave a space between the second and the third
TextViews for placing the button that will initiate the calculation.
I have changed the text font sizes to 18 sp and made the text type bold. The
layout seems like in Figure 6.4 after changing the texts of these TextViews
per our aim.
109 | P a g e
Figure 6.4. The app’s GUI layout after setting up the TextViews
The positioning of the Text Fields (text boxes) are shown in Figure 6.5. I’ve
placed Text Fields which can be used to input decimal numbers (numbers
with fractional part) rather than general input types because the user is
supposed to enter only numeric values in this app. It is worth noting that
the calculation result will be displayed next to the Your BMI: label and a
Text Field is placed there to display the BMI result.
We could use a static text (TextView) for this aim however I wanted to show
you how we can set the contents of the TextField programmatically.
110 | P a g e
Figure 6.5. Placing the TextFields
Please note that Text Fields do not have borders by default therefore after
they are placed, we can only see them by selecting them.
Let‟s set their IDs so that we can access them programmatically and also
set their default texts. For this, select the respective TextField and then set
the ID and text properties as shown in Figure 6.6 for the weight input Text
Field. I also positioned its default text in the middle as we did before.
111 | P a g e
Figure 6.6. Settings of the weight input TextField
Figure 6.7. The GUI of the app after setting up all TextFields
Please set the IDs and default texts of the height input and BMI result Text
Fields as heightInput and 1.80; BMIResult and ……., respectively. Bu
setting the default text of the BMI result Text Field as
……., we make the user to see ……. in that box before calculating his/her
BMI. After these settings, the GUI seems as in Figure 6.7.
112 | P a g e
widget from the Palette between the height input TextView and the YourBMI
TextView and then position it horizontally in the middle as shown below:
Now, please set the text of the button as Calculate my BMI! Note that the
default ID of the button is button which is OK.
Our GUI is almost complete however there’s one step remaining. The ID of
the BMI category TextView (the one with the text Your BMI category
appears here.). Please set its ID as BMICategory and then we are finished.
After these steps, the GUI of our app is ready as shown below:
113 | P a g e
Figure 6.9. The GUI of our BMI Calculator app
Firstly, the values entered in the weight input and height input text fields
will be taken. These will be String type variables.
Convert these Strings to double type variables so that the BMI calculation
can be performed using the BMI equation given at the beginning of the
chapter.
Perform the body mass index calculation.
Display the BMI value in the text field next to the “Your BMI:” label after
converting to String type.
Use if–else statements to determine the BMI category from the BMI value
using Table 6.1.
Display the BMI category in the text view which shows “BMI category
appears here.” by default.
114 | P a g e
Please open the MainActivity.java file from the file explorer of Android
Studio. The default contents of this file are as follows:
package com.helloworld.quantum.bmicalculator;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Code 6.1
The calculation will be done when the user taps the button therefore we
need to write a listener method for the button and then call this method
inside the onCreate() function (as we explained in the previous chapter). Code
6.2 shows the general template of the button listener method.
public void
myButtonListenerMethod() {
Button button = (Button)
findViewById(R.id.button);
button.setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
115 | P a g e
// code those will be run when the
button’s clicked
}
});
}
Code 6.2
First of all we need to take the height and weight inputs from their
respective EditTexts (TextFields). This is simply done with the following
code snippet:
In the first line, we access the height input textbox using its ID
(R.id.heightInput) and then create an EditText object called
heightText.
In the second line, the string inside this EditText is extracted and
assigned to a new String object called heightStr .
And in the last line, the String value of the height is converted to double
type and assigned to a newly created variable height .
116 | P a g e
In the end, we have the height value stored in the height variable which is
of double type.
The following code does a similar job and in the end the weight value is
stored in the weight variable.
We now have weight and height data in double type variables so we can do
the BMI calculation using the equation given in the beginning of the
chapter as follows:
In this code, the * operator does the multiplication while the / operator
divides the weight to the height squared.
We will display this BMI value in the EditText box next to the You BMI
label in the GUI. We did set its ID as BMIResult when we laid out the user
interface before. Therefore, the following code does this job:
BMIResult.setText(Double.toString(BMI));
Code 6.6
117 | P a g e
In this code, the widget with the ID BMIResult is found in the first line and
then the double type BMI variable is converted to String by the code
Double.toString(BMI) for displaying inside the EditText. Note that the texts written
inside the EditText widgets can only be read and written as Strings.
We now have the BMI stored as a double type variable. We now have to use
if–else statements to check this numeric value according to Table 6.1 and
determine the BMI category. For this, let’s define a String that will hold the
BMI category:
String BMI_Cat;
Code 6.7
We‟ll set this String according to the BMI value using if–else statements as
follows:
if (BMI < 15)
BMI_Cat = "Very severely underweight";
else if (BMI < 16)
BMI_Cat = "Severely underweight";
else if (BMI < 18.5)
BMI_Cat = "Underweight";
else if (BMI < 25)
BMI_Cat = "Normal";
else if (BMI < 30)
BMI_Cat = "Overweight";
else if (BMI < 35)
BMI_Cat = "Obese Class 1 - Moderately Obese";
else if (BMI < 40)
BMI_Cat = "Obese Class 2 - Severely Obese";
else
BMI_Cat = "Obese Class 3 - Very Severely Obese";
Code 6.8
118 | P a g e
The only thing remaining is setting the TextView to the BMI_Cat String so that
the BMI category is displayed in the user interface:
Please note that the library import directives at the beginning of this file are
automatically placed by Android Studio according to the methods and
classes we used in our code.
119 | P a g e
package com.helloworld.quantum.bmicalculator;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButtonListenerMethod();
}
public void myButtonListenerMethod() {
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
final EditText heightText = (EditText)
findViewById(R.id.heightInput);
String heightStr = heightText.getText().toString();
120 | P a g e
double height = Double.parseDouble(heightStr);
final EditText weightText = (EditText)
findViewById(R.id.weightInput);
String weightStr = weightText.getText().toString();
double weight = Double.parseDouble(weightStr);
double BMI = (weight)/(height*height);
final EditText BMIResult = (EditText)
findViewById(R.id.BMIResult);
BMIResult.setText(Double.toString(BMI)); String BMI_Cat;
if (BMI < 15)
BMI_Cat = "Very severely underweight";
else if (BMI < 16)
BMI_Cat = "Severely underweight";
else if (BMI < 18.5)
BMI_Cat = "Underweight";
else if (BMI < 25)
BMI_Cat = "Normal";
else if (BMI < 30)
BMI_Cat = "Overweight";
else if (BMI < 35)
BMI_Cat = "Obese Class 1 – Moderately
Obese";
else if (BMI < 40)
BMI_Cat = "Obese Class 2 - Severely Obese";
else
BMI_Cat = "Obese Class 3 - Very Severely
Obese";
final TextView BMICategory =
(TextView)
findViewById(R.id.BMICategory);
121 | P a g e
BMICategory.setText(BMI_Cat);
}
});
}
}
Code 6.10 (cont’d from the previous page)
Enter weight and height values (in kg and meters) and then tap the
CALCULATE MY BMI! button. If you followed all steps correctly, you
should see the BMI value and the BMI category on your app screen as in
Figure 6.11.
122 | P a g e
Figure 6.11. A sample BMI calculation
The DecimalFormat class is used for these types of operations. Android Studio
automatically adds the required library by the code line:
import android.icu.text.DecimalFormat;
Code 6.12
123 | P a g e
package com.helloworld.quantum.bmicalculator;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButtonListenerMethod();
}
public void myButtonListenerMethod() {
Button button = (Button)findViewById(R.id.button);
124 | P a g e
button.setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
final EditText heightText =
(EditText)
findViewById(R.id.heightInput);
String heightStr =
heightText.getText().toString();
double height =
Double.parseDouble(heightStr);
final EditText weightText =
(EditText)
findViewById(R.id.weightInput);
String weightStr =
weightText.getText().toString();
double weight =
Double.parseDouble(weightStr);
125 | P a g e
String BMI_Cat;
126 | P a g e
}
Code 6.13 (cont’d from the previous page)
When the modified code is used, the calculation result is displayed in the
emulator as follows:
Figure 6.12. The sample BMI calculation with trimmed BMI digits
Note 2. I have verified that our BMI Calculator app works as expected on a
real device (Asus Zenfone 6).
Note 3. Don‟t worry if the app categorizes you obese, it does me too (the
values shown in Figure 6.12 are not mine). Please consult your doctor
and dietician for the ways of decreasing your BMI like regularly exercising
and eating less processed food.
We‟ll develop a dice rolling app in the next chapter where you will learn
adding dynamic images to your app and utilizing randomness functions in
Android. See you after a strong coffee!
127 | P a g e
ANDRIOD APP #3: SIMPLE DICE ROLLER
7.1. Creating the Project and Adding an Imageview Widget
We‟ll develop a simple dice rolling app in this chapter. We‟ll learn how to
use images in the GUI and also code for basic random number generation
in Java for rolling a virtual dice. When we hit a Roll button, the app will
choose a number between 1 and 6 randomly, show the result as a number
in a TextView and also display a dice image that shows the outcome.
Please create a new project and save it on your computer. Select an empty
activity as usual. I named my project as Dice Roller but you can of course
give any name you’d like.
First of all, let’s design the user interface. While the activity_main.xml file is
opened in Android Studio, please change the default Textview’s text from
Hello World to Dice Roller and position it on the top of the GUI aligned
horizontally in the middle as shown in Figure 7.1.
128 | P a g e
Figure 7.1. TextView showing the title of the app
Figure 7.2. Dice face images and their filenames used in the app Please
select and right-click copy all of these images in the file explorer of your
computer (just as you do when you select files for copypaste) and then
right-click paste in the drawable folder in Android Studio as shown
below:
129 | P a g e
Figure 7.3. Adding image files to the Android Studio project
When we click the arrow symbol just at the left of drawable folder, we can
see the newly added image files as in Figure 7.4.
Let‟s place the ImageView object to the GUI now. Please find the ImageView
object in the Palette and drag and drop to the app’s layout as follows:
130 | P a g e
Figure 7.5. Adding an ImageView object
When we drop the ImageView on the GUI, Android Studio wants us to set
its image as in Figure 7.6. The selected image will be the image shown
inside the ImageView when the app first starts (i.e. default image).
Therefore, please select the dicegeneral.png as in Figure 7.6.
131 | P a g e
Figure 7.6. Selecting the default image for the ImageView
After this selection, press OK and then the layout of our app will be shown
as follows:
7.2. Adding the Other Widgets and Setting up the IDs Please place a
TextView and a Button just below the ImageView object which will display
the result of the rolling and initiate the rolling, respectively. I have set the
TextView to show Please tap the button…. Similarly, the button’s text is
changed to ROLL! as shown below:
132 | P a g e
Figure 7.8. The GUI after placing all of the required objects
We‟ll need the IDs of the dice image, the result TextView and the button
because we‟ll access them in the code. I’ve assigned their IDs as
diceImage, rollResult and rollButton, respectively.
133 | P a g e
public void onClick(View v) {
});
}
Code 7.1
In this code, a Random object called rand is created in the first line. In the
second line, the method nextInt() is applied on this object by rand.nextInt(6).
The nextInt(int n) method generates random numbers between 0 and n–1
therefore rand.nextInt(6) generates random numbers between 0 and 5. Therefore
the expression rand.nextInt(6) + 1 gives random numbers between 1 and 6
for simulating a dice. This random number is assigned to the integer
variable rollResult.
We‟ll display the rollResult integer in the diceResult TextView on the user
interface. In the following code, a TextView object is created to access the
diceResult TextView and then its text is set as Integer.toString(rollResult)
which is the String expression of rollResult :
The last thing we need to add is the code to change the ImageView’s image
according to the rolling result. Firstly, we will access the ImageView object
using the following code line:
134 | P a g e
ImageView img = (ImageView)
findViewById(R.id.diceImage);
Code 7.4
Since the rolling result is an integer number, we can easily utilize the
switch–case statements to change the image as follows:
switch (rollResult) {
case 1: img.setImageResource(R.drawable.dice1);
break;
case 2: img.setImageResource(R.drawable.dice2);
break;
case 3: img.setImageResource(R.drawable.dice3);
break;
case 4: img.setImageResource(R.drawable.dice4);
break;
case 5: img.setImageResource(R.drawable.dice5);
break;
case 6: img.setImageResource(R.drawable.dice6);
break;
}
Code 7.5
Please note that we change the image of the ImageView object img with the
method setImageResource() which takes the image resource with the template
R.drawable.”imagename”.
Combining all these code lines and calling the button listener method
inside the onCreate() method of the activity, we reach the complete
MainActivity.java given below:
135 | P a g e
package com.helloworld.quantum.myapplication; import
android.support.v7.app.AppCompatActivity; import
android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.Random;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButtonListenerMethod();
} public void myButtonListenerMethod() {
Button button = (Button)
findViewById(R.id.rollButton);
button.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v) {
Random rand = new Random();
int rollResult = rand.nextInt(6) + 1;
136 | P a g e
findViewById(R.id.diceResult);
diceResult.setText(Integer.toString(rollResult));
case 4: img.setImageResource(R.drawable.dice4);
break;
case 5: img.setImageResource(R.drawable.dice5);
break;
case 6: img.setImageResource(R.drawable.dice6);
break; }
}
});
}
}
Code 7.6 (cont’d from the previous page)
137 | P a g e
7.4. Building and Running the App
Let‟s run our dice roller app by hitting the “Run” button in Android Studio
and selecting an emulator such as Nexus 4 as we did before. The app
shown in Figure 7.9 appears. Each time you click the ROLL! button, the
app should show a different number with the corresponding die face image
as in Figure 7.10. The app also works properly on a real device as it should.
It is worth noting that random numbers are not only used for fun apps but
also in everyday cryptographic processes like online credit card
transactions, etc. Hence there are much more sophisticated random
number generation functions in Java and Android, also with the aid of
external libraries. However for simple randomness like in our die rolling
game, the Random class seems adequate. You can check its randomness by
consecutively clicking on the Roll! button and observing if you obtain the
same number a lot or if the numbers show a pattern that you can guess the
next number. However please keep in mind that accurate testing of
randomness requires complex tools.
Let‟s take a short break before continuing to the next chapter where we‟ll
develop a compass app which will utilize the internal accelerometer and
magnetometer sensor of the device.
138 | P a g e
Figure 7.9. The app when it is first run
139 | P a g e
As we develop our compass app, we‟ll learn setting permissions to use
sensors, reading acceleration and magnetic field data in Java code,
extracting the orientation data from the sensor data and animating images.
In the end, we‟ll have a complete compass app that we can use in daily life.
We‟ll need a compass image whose needle shows the absolute north. I
found the royalty free image shown in Figure 8.1 for this aim (I chose this
one because it looks sort of ancient like an ancient compass ). You can
download this image from the book’s companion website as usual. You can
of course use any other image you like in your project. Please copy and
paste this image to your drawable folder as we did before. The name of the
image is compass.png, we‟ll use its name to access it in our code.
140 | P a g e
Figure 8.2. The AndroidManifest file in the project explorer
Open this file by double clicking on it in Android Studio and you‟ll see its
default contents as shown in Figure 8.3. Please add the lines shown in
Code 8.1 to this file before the <application> tag and you‟ll obtain the
finalized contents as shown in Code 8.2. These lines make the
accelerometer and magnetometer outputs available to be used in our app.
<uses-feature
android:name="android.hardware.sensor.accelerometer"
android:required="true" />
141 | P a g e
<uses-feature
android:name="android.hardware.sensor.magnetometer"
android:required="true" />
Code 8.1
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
142 | P a g e
</application>
</manifest>
Code 8.2 (cont’d from the pervious page)
Figure 8.4. The TextView used to display the title of the app
Let’s now place an ImageView in the middle of the GUI and select the
compass image that we pasted to the drawable folder:
143 | P a g e
Figure 8.5. Selecting the compass image for the ImageView component
After we place the ImageView, it’ll be selected. Then, please set up its ID as
iv_compass (short for ImageView_compass) from the right pane of Android
Studio as follows:
Finally, let’s place a TextView below the ImageView in which we‟ll display
the orientation angle in real time. I set its ID as tv_degrees (short for
TextView_degrees), and made it 24sp with a bold text as shown below:
144 | P a g e
8.3. Writing the Main Code of the App
We completed the design of the user interface and now ready to continue
with the coding. Please open the MainActivity.java file in Android Studio.
This file will have the default contents as follows:
package com.example.atomic.compassapp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Code 8.3
Float azimuth_angle;
Code 8.4
Finally, let’s declare ImageView and TextView objects which will be used to
access the corresponding components in the GUI:
TextView tv_degrees;
ImageView iv_compass;
Code 8.6
We can place these declarations inside the MainActivity class just before
the onCreate() method. Then, we can assign the default accelerometer and
magnetometer sensors to their objects inside the onCreate() method as
follows:
compassSensorManager =
(SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer =
compassSensorManager.getDefaultSensor(Sensor.TYPE_ACC
ELEROMETER);
magnetometer =
compassSensorManager.getDefaultSensor(Sensor.TYPE_MAG
NETIC_FIELD);
Code 8.7
package com.example.atomic.compassapp;
import android.hardware.Sensor;
import
146 | P a g e
android.hardware.SensorManager;
import
android.support.v7.app.AppCompatAct
ivity; import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
Float azimuth_angle;
private SensorManager
compassSensorManager;
Sensor accelerometer;
Sensor magnetometer;
TextView tv_degrees;
ImageView iv_compass;
@Override
protected void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
compassSensorManager =
(SensorManager)getSystemService(SENSOR_
SERVICE); accelerometer =
compassSensorManager.getDefaultSensor(S
ensor.TYPE_ACC ELEROMETER);
magnetometer =
compassSensorManager.getDefaultSensor(S
ensor.TYPE_MAG
147 | P a g e
NETIC_FIELD);
}
}
Code 8.8
Please click the Implement methods and then Android Studio will
automatically place the onSensorChanged() and
onSensorActivityChanged() methods when we click the OK button in the
dialog box:
148 | P a g e
Figure 8.9. Dialog showing the methods which will be implemented
Android Studio automatically places the following code to
MainActivity.java:
@Override
public void onSensorChanged(SensorEvent event) {
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
Code 8.10
We‟ll write our main code inside the onSensorChanged() method. However, before
moving on to the main code, let’s write the onResume() and onPause() methods for
the main activity because sensors are power hungry components therefore
it is important to pause and resume the sensor listeners when the activity
pauses and resumes. For this, we simply add the following code just below
the end of the onCreate() method:
protected void onResume() { super.onResume();
mSensorManager.registerListener(
this, accelerometer,
149 | P a g e
SensorManager.SENSOR_DELAY_UI);
mSensorManager.registerListener(this,
magnetometer, SensorManager.SENSOR_DELAY_UI);
} protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this); }
Code 8.11
In the onResume() method, the sensor listeners are registered meaning that the
sensors are powered on again when the activity resumes.
Similarly, the sensors are unregistered (disconnected) in the onPause() method
when the activity pauses.
We’re now ready to write the main code. Firstly, let’s define two float type
arrays to hold the accelerometer and magnetometer output data. These will
be array variables because the outputs of these sensors are vectoral
quantities i.e. they have different values for different directions.
We can define the arrays named accel_read and magnetic_read for these
sensors as follows:
float[] accel_read;
float[] magnetic_read;
Code 8.12
Please write these declarations just before the onSensorChanged() method so that
we can access these variables from anywhere in the onSensorChanged() method.
150 | P a g e
tv_degrees =(TextView) findViewById(R.id.tv_degrees); iv_compass =
(ImageView) findViewById(R.id.iv_compass);
Code 8.13
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
accel_read = event.values;
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
magnetic_read = event.values;
Code 8.14
If the sensor outputs are available (i.e. they are not null), we‟ll use the
accel_read and magnetic_read variables in the method called getRotationMatrix()
151 | P a g e
float degrees = ((azimuth_angle * 180f) / 3.14f);
int degreesInt = Math.round(degrees);
tv_degrees.setText(Integer.toString(degreesInt) +
(char) 0x00B0 + " to absolute north."); }
Code 8.16
In this code:
It is also good to rotate the compass image according to the azimuth angle.
For this animation, we need to declare a float type variable which will hold
the current value of the ImageView’s rotation degree:
Then, we can use the following animation code which will rotate the
ImageView according to the azimuth angle:
152 | P a g e
RotateAnimation rotate = new
RotateAnimation(current_degree, -
degreesInt,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(100);
rotate.setFillAfter(true);
iv_compass.startAnimation(r
otate); current_degree = -
degreesInt;
Code 8.18
153 | P a g e
public class MainActivity extends AppCompatActivity
implements SensorEventListener {
Float azimuth_angle;
private SensorManager compassSensorManager;
Sensor accelerometer;
Sensor magnetometer;
TextView tv_degrees;
ImageView iv_compass;
private float current_degree = 0f;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
compassSensorManager =
(SensorManager)getSystemService(SENSOR_SERVICE);
accelerometer =
compassSensorManager.getDefaultSensor(Sensor.TYPE_ACC
ELEROMETER);
magnetometer =
compassSensorManager.getDefaultSensor(Sensor.TYPE_MAG
NETIC_FIELD);
} protected void onResume() {
super.onResume();
compassSensorManager.registerListener(this, accelerometer,
SensorManager.SENSOR_DELAY_UI);
compassSensorManager.registerListener(this, magnetometer,
154 | P a g e
SensorManager.SENSOR_DELAY_UI);
} protected void onPause() {
super.onPause();
compassSensorManager.unregisterListener(this);
}
float[] accel_read; float[] magnetic_read;
@Override
public void onSensorChanged(SensorEvent event) {
tv_degrees =(TextView) findViewById(R.id.tv_degrees);
iv_compass = (ImageView) findViewById(R.id.iv_compass);
if (event.sensor.getType() ==
Sensor.TYPE_ACCELEROMETER)
accel_read = event.values;
if (event.sensor.getType() ==
Sensor.TYPE_MAGNETIC_FIELD)
magnetic_read = event.values;
if (accel_read != null && magnetic_read != null) {
float R[] = new float[9]; float I[] = new float[9];
boolean successsful_read =
SensorManager.getRotationMatrix(R, I, accel_read,
magnetic_read); if (successsful_read) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimuth_angle = orientation[0];
float degrees = ((azimuth_angle * 180f) /
3.14f);
int degreesInt = Math.round(degrees);
tv_degrees.setText(Integer.toString(degreesInt)
155 | P a g e
+ (char) 0x00B0 + " to absolute north.");
RotateAnimation rotate = new
RotateAnimation(current_degree, -degreesInt,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotate.setDuration(100);
rotate.setFillAfter(true);
iv_compass.startAnimation(rotate);
current_degree = -degreesInt;
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}
156 | P a g e
Figure 8.10. Compass app running on a real device
Now, let’s take a break and get a strong coffee. In the next chapter, we‟ll
learn using GPS and maps in our app.
157 | P a g e
ANDRIOD APP # 5: SHOW MY LOCATION: USING GPS AND MAPS
9.1. Creating a Map Project
Geolocation and navigation apps are popular in all mobile platforms.
Considering this, most mobile devices especially smartphones include
components called GPS receivers. These receivers take microwave band
radio signals from global positioning satellites that move in specified orbits
around the earth. These GPS signals are extremely weak but thanks to the
electronics tech, amplifier and processing circuits in smartphones can
utilize these signals for location services.
Anyway, let’s start developing our 5th app: Show My Location. In this
chapter, you‟ll learn to use maps and geolocation data from GPS in your
apps. It sounds easy but there are some confusing tricks to use the GPS
receiver; don‟t worry I’ll show all of them in a while.
In this app, we aim to show our real time location on the map.
Let‟s start with creating a new Android project and select Google Maps
Activity as the activity type a shown in Figure 9.1. When we select the
Google Maps Activity, the main Java file and the xml layout file of the
project are named as MapsActivity.java and activity_maps.xml
automatically as in Figure 9.2.
158 | P a g e
Figure 9.1. Selecting Google Maps Activity during the project creation
<resources>
<!--
TODO: Before you run your application, you need a Google Maps API
key.
To get one, follow this link, follow the directions and press "Create"
at the end:
https://console.developers.google.com/flows/enableapi ?
apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDRO
ID&r=F7:42:43:B5:F0:19:50:79:4E:0E:69:D2:1A:27:3D:7D:
E4:47:EC:6D%3Bcom.example.atomic.myapplication
160 | P a g e
Figure 9.4. Creating a new project to obtain a new api key for the maps app
Google console will then display the generated api key as shown below:
Please copy the generated api key and paste it to the place indicated in the
google_maps_api.xml file:
161 | P a g e
<resources>
<!--
TODO: Before you run your application, you need a Google Maps API
key.
To get one, follow this link, follow the directions and press "Create"
at the end:
https://console.developers.google.com/flows/enableapi ?
apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDRO
ID&r=F7:42:43:B5:F0:19:50:79:4E:0E:69:D2:1A:27:3D:7D:
E4:47:EC:6D%3Bcom.example.atomic.myapplication
Please note that you need to generate and paste your own key otherwise
your app won’t work.
162 | P a g e
package com.example.atomic.myapplication;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import
com.google.android.gms.m
aps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps); // Obtain the
SupportMapFragment and get notified when the map is ready
to be used.
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available. * This callback is
163 | P a g e
triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or
move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the
user will be prompted to install * it inside the
SupportMapFragment. This method will only be triggered once
the user has
* installed Google Play services and returned to the app.
*/ @Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
If you see the map with the marker, congratulations. If you cannot see the
map, please check the api key section above. Most errors are caused from a
wrong api key unless there’s another error indicated by the gradle building
system.
165 | P a g e
9.5. Implementing the Required Callbacks
We now need to take data from the GPS receiver and then show our current
location on the map rather than the default marker. For this, we first
implement the required callbacks in the main class definition as follows:
166 | P a g e
Figure 9.8. Selecting Implement methods for correcting the callbacks
package com.example.atomic.myapplication;
import android.location.Location;
import android.location.LocationListener;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
167 | P a g e
import android.os.Bundle;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps); // Obtain the
SupportMapFragment and get notified when the map is ready to be
used.
SupportMapFragment mapFragment =
(SupportMapFragment)
getSupportFragmentManager() .findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
168 | P a g e
* Manipulates the map once available. * This callback is triggered
when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move
the camera. In this case, * we just add a marker near Sydney,
Australia.
* If Google Play services is not installed on
@Override
public void onLocationChanged(Location location) {
@Override
public void onStatusChanged(String provider, int status, Bundle
extras) {
169 | P a g e
@Override
public void onProviderEnabled(String provider)
{
@Override
public void onProviderDisabled(String provider) {
@Override
public void onConnected(@Nullable Bundle
bundle) {
}
@Override
public void onConnectionSuspended(int i) {
@Override
public void onConnectionFailed(@NonNull
ConnectionResult connectionResult) {
}
}
Code 9.5 (cont’d from the previous page)
The onCreate() method contains the jobs to be done when the activity first
starts as we learned before. We need to modify it as follows to check the
location tracking permission and create a SupportMapFragment object
that will be used to do things related to the MapFragment object of the user
interface:
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
if (android.os.Build.VERSION.SDK_INT >=
Build.VERSION_CODES.M) {
checkLocationPermission();
}
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this); }
Code 9.7 (cont’d from the previous page)
The next method to modify is the onMapReady() method. This method deals with
the manipulation of the map once it is available. In this method, the app
171 | P a g e
will check whether the device has Google Play Services installed and if not,
the app will prompt to install it. Please remember that map related
functions cannot run if Google Play Services is not installed. We do these as
follows:
public void onMapReady(GoogleMap googleMap) { mMap =
googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
The Google api client used in this method is built using the following
method:
protected synchronized void buildGoogleApiClient()
{ myGoogleApiClient = new
GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
172 | P a g e
.addApi(LocationServices.API)
.build();
myGoogleApiClient.connect(); }
Code 9.9
When the required permissions are taken and Google api is ready, the app
will start tracking the current location inside the onConnected() method as
follows:
public void onConnected(Bundle bundle) {
myLocationRequest = new LocationRequest();
myLocationRequest.setInterval(1000);
myLocationRequest.setFastestInterval(1000);
myLocationRequest.setPriority(LocationRequest.PRIORIT
Y_BALANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(myGoogl
eApiClient, myLocationRequest, this);
}
}
Code 9.10
In this code, the time intervals are shown in milliseconds. Therefore, the
location data is gathered in 1 second intervals. If the intervals get more
frequent, the location data will be gathered in shorter intervals but this will
drain the battery faster. The setPriority() method is also used to manage the
power consumption. In this code, a balanced power usage is selected.
173 | P a g e
When the location changes, the app will move the marker to the new
location. This is done inside the onLocationChanged() method:
myLastLocation = location;
if (myCurrLocationMarker != null) {
myCurrLocationMarker.remove();
}
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(Bitma
pDescriptorFactory.HUE_MAGENTA)); myCurrLocationMarker =
mMap.addMarker(markerOptions);
LocationServices.FusedLocationApi.removeLocationUpdat
es(myGoogleApiClient, this);
174 | P a g e
}
}
Code 9.11
ActivityCompat.requestPermissions(
this, new String[]{Manifest.permission.
ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
} else {
ActivityCompat.requestPermissions(
this, new String[]{Manifest.permission.
175 | P a g e
ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
return false;
} else {
return true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults)
{ switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
176 | P a g e
Toast.LENGTH_LONG).show();
} return;
}
}
Code 9.12 (cont’d from the previous page)
These methods ask for user permission to track fine location. If the user
rejects giving the permission, the message “Permission not given.” is
shown on the screen as a popup dialog.
import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
177 | P a g e
importcom.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
178 | P a g e
}
@Override
public void onMapReady(GoogleMap googleMap) { mMap =
googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED)
{
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
} } else {
buildGoogleApiClient();
mMap.setMyLocationEnabled(true);
}
}
179 | P a g e
}
@Override
public void onConnected(Bundle bundle) {
180 | P a g e
myLocationRequest.setPriority(LocationRequest.PRIORITY_BAL
ANCED_POWER_ACCURACY);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
LocationServices.FusedLocationApi.requestLocationUpdates(
myGoogleApiClient, myLocationRequest, this);
}
@Override
public void onConnectionSuspended(int i) {
@Override
public void onLocationChanged(Location location) {
myLastLocation = location;
if (myCurrLocationMarker != null) {
myCurrLocationMarker.remove();
}
LatLng latLng = new LatLng(location.getLatitude(),
location.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(latLng);
markerOptions.title("My Position");
markerOptions.icon(BitmapDescriptorFactory.defaultMarker(B
181 | P a g e
itmapDescriptorFactory.HUE_MAGENTA));
myCurrLocationMarker = mMap.addMarker(markerOptions);
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(11));
if (myGoogleApiClient != null) {
LocationServices.FusedLocationApi.removeLocationUpdates(my
GoogleApiClient, this);
}
@Override
public void onConnectionFailed(ConnectionResult
connectionResult) {
}
public static final int
MY_PERMISSIONS_REQUEST_LOCATION = 99;
public boolean checkLocationPermission(){
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if
(ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
ActivityCompat.requestPermissions(
this, new
182 | P a g e
String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
} else {
ActivityCompat.requestPermissions(
this, new
String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
return false; } else {
return true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[]
grantResults) { switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
PackageManager.PERMISSION_GRANTED) {
if
(ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
==
PackageManager.PERMISSION_GRANTED) {
183 | P a g e
if (myGoogleApiClient == null)
{ buildGoogleApiClient();
}
mMap.setMyLocationEnabled(true);
}
} else {
Please remember that you can download these files from the book’s
companion website: www.android-java.website.
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.atomic.myapplication">
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
184 | P a g e
<uses-permission
android:name="android.permission.INTERNET" />
<uses-permission
android:name="com.google.android.providers.gsf.permission.
READ_GSERVICES" />
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not
required to use
Google Maps Android API v2, but you must specify either
coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--
The API key for Google Maps-based APIs is defined as a
string resource.
(See the file
"res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to
sign the APK.
You need a different API key for each encryption key,
185 | P a g e
including the release key that is used to sign the APK for
publishing.
You can define the keys for the debug and release targets in
src/debug/ and src/release/.
--> <meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key"/>
<activity
android:name=".MapsActivity"
android:label="@string/title_activity_maps">
<intent-filter>
<action
android:name="android.intent.action.MAIN"/>
<category
android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
The Internet and GPS permissions are added because the map uses both
coarse and fine location tracking.
186 | P a g e
9.8. Running Our App and Sending Custom Coordinates to the
Emulator
Please hit the Run button in Android Studio to run our Show My Location
app. You can run the app in an emulator or on an actual device. The app
running in the Nexus 4 emulator is shown in Figure 9.10. If you cannot see
the map on your app, most probably it’s an error regarding the api key.
Please review that section again.
Please note that I have sent custom coordinates to the emulator using its
options button as shown in Figure 9.11. The latitude and longitude of the
coordinates I’ve entered are 41.3809 N and 2.11287 E. Can you guess what
this famous location is?
Hint: You can zoom in and out on the emulator’s map by double-clicking
at a point and then moving the mouse up or down.
It is worth noting that I’ve tried the app on a real device and it works as
expected.
187 | P a g e
CHAPTER 9. ANDRIOD APP #5: SHOW MY LOCATION
188 | P a g e
Figure 9.10. Our Show My Location app in the emulator
189 | P a g e
Figure 9.11. Sending custom coordinates to the emulator
190 | P a g e
ANDRIOD APP # 6: S.O.S. MESSAGE SENDER
10.1. Introduction
Most of the Android devices have the capability of GSM connection
therefore it is useful to learn using SMS messaging in Android. A class
called SmsManager enables us to design apps that can easily send and receive
SMS programmatically. You‟ll see how this class is used in this chapter.
<manifest
xmlns:android="http://schemas.android.com/apk/res/and roid"
package="sendsms.example.com.sendsms">
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION
" />
<uses-permission
android:name="android.permission.SEND_SMS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Code 10.2 (cont’d from the previous page)
192 | P a g e
10.2. Designing the User Interface
Let‟s design the user interface now. The user will basically click on an
S.O.S. button and nothing else is needed. Therefore, I placed a button
widget in the middle the screen in the activity_main.xml file as in Figure
10.1 and set its label as S.O.S.
Let‟s change the button’s background colour to red. For this, firstly click
the View all properties button as indicated by the arrow in Figure 10.3. In
the properties list appearing as in Figure 10.4, find the background
property as indicated in Figure 10.5.
193 | P a g e
Figure 10.2. Setting the button’s dimensions
194 | P a g e
Figure 10.4. All the properties of the button widget shown in the right pane
A box in which we can enter the hex colour code of the background will
appear as follows:
195 | P a g e
Figure 10.6. Custom colour code entry box
We’ve set the background colour, great. However the S.O.S. label of the
button seems tiny now. Let‟s edit its properties. As the first step, let’s
196 | P a g e
switch back to the popular properties of the button by clicking the View all
properties button again as indicated in Figure 10.8.
I’ve set the text size as 72sp and its type as bold as shown in Figure 10.9.
197 | P a g e
Figure 10.9. Setting the text size and type
The app will take longitude and latitude data from the GPS receiver. This
data is a floating point number therefore let’s declare two double type
variables to hold the location data as follows:
double latitude = 0;
double longitude = 0;
Code 10.3
Let‟s define a GPSReceiver class to manage the GPS part with the LocationListener
Android Studio will warn us for implementing the required methods at this
point:
198 | P a g e
Hit OK in this dialog and the methods onLocationChanged() , onStatus(),
onProviderEnabled() and onProviderDisabled() will be added to the
MainActivity.java. onStatusChanged() is called when a change in the location
occurs. Similarly, onProviderEnabled() and onProviderDisabled()
methods are called when the GPS receiver is enabled and disabled,
respectively. onStatusChanged() is called if the GPS status is changed.
@Override
public void onProviderEnabled(String s)
{ Toast.makeText(getApplicationContext(), "GPS
Enabled!", Toast.LENGTH_LONG).show();
}
@Override
public void onProviderDisabled(String s) {
}
}
Code 10.5
199 | P a g e
onLocationChanged() method. Firstly, let’s define a location object which
will hold the location data just after the longitude and latitude variable
declarations as follows:
If the location data isn’t null, i.e. if the location data is received
successfully, the longitude and latitude data will be assigned to longitude
and latitude variables, respectively. getLongitude() and getLatitude()
methods extract the longitude and latitude data from the location object. If the
location data is received without any problem, a dialog will display “READY
TO SEND!” text on the screen otherwise it’ll write “NOT READY YET...”.
We’ve declared our custom method for handling the GPS data operations.
Now it’s time to define a GPSReceiver object as follows:
Next, let’s create the button listener method which will do the SMS sending
when the sendSOS button’s clicked:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SmsManager sms = SmsManager.getDefault();
String phoneNumber = "xxxxxxxxxxxx";
String messageBody = "Please take me from
longitude: " + Double.toString(longitude) + " and latitude: " +
Double.toString(latitude);
try {
sms.sendTextMessage(phoneNumber, null,
messageBody ,null, null);
Toast.makeText(getApplicationContext(),
"S.O.S. message sent!", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Message
sending failed!!!", Toast.LENGTH_LONG).show();
}
}
});
}
Code 10.9 (con’t from the previous page) In this
button listener method:
201 | P a g e
The button object is created at first,
Then an SmsManager object called sms is declared inside the onClick() method,
Next, the phone number which will receive our SMS is defined in the
variable named phoneNumber (please enter a valid receiving phone
number in the place of xxxxxxxxxx!!!),
The messageBody is also declared as a String using the longitude and latitude
data.
Finally, the SMS is sent programmatically by the sendTextMessage() method.
The try – catch statement is used to check if there’s an error sending
the SMS message. If there’s no error, a message saying “S.O.S. message
sent!” will be displayed. Otherwise, it’ll display “Message sending
failed!!!”.
As you can see, the sendTextMessage() method has five arguments. We’ve set the
unused arguments to null. We could use these unused arguments for
extended functionality such as checking if the SMS is actually received by
the receiving part.
Finally, we need to call the button listener and GPS related methods inside
the onCreate() method as usual:
202 | P a g e
The complete MainActivity.java is also given as follows:
package sendsms.example.com.sendsms;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.icu.text.DecimalFormat;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.util.function.DoubleUnaryOperator;
@Override
protected void onCreate(Bundle
savedInstanceState) {
203 | P a g e
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myButtonListenerMethod(); receiver = new GPSReceiver();
manager = (LocationManager)
this.getSystemService(Context.LOCATION_SERVICE);
manager.requestLocationUpdates(LocationManager.GPS_PR
OVIDER, 1000L, 1.0F, receiver);
}
public void myButtonListenerMethod() {
Button button = (Button) findViewById(R.id.sendSOS);
button.setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
SmsManager sms =
SmsManager.getDefault();
String phoneNumber = "05363624223";
String messageBody = "Please take me from longitude: " +
Double.toString(longitude) + " and latitude: " +
Double.toString(latitude); try {
sms.sendTextMessage(phoneNumber, null,
messageBody ,null, null);
Toast.makeText(getApplicationContext(), "S.O.S.
message sent!", Toast.LENGTH_LONG).show();
} catch (Exception e) {
@Override
public void onStatusChanged(String s, int i,
Bundle bundle) {
@Override
public void onProviderEnabled(String s)
{
Toast.makeText(getApplicationContext(), "GPS
Enabled!", Toast.LENGTH_LONG).show();
}
205 | P a g e
@Override
public void onProviderDisabled(String s) {
Toast.makeText(getApplicationContext(),
"Please enable GPS!", Toast.LENGTH_LONG).show();
}
}
}
When the app starts, please wait a moment to see the READY TO SEND!
message on the screen and then if you click on the giant S.O.S. button, the
phone will send your current location to the hardcoded phone number. In
the receiving phone, you‟ll see a text such as Please take me from
206 | P a g e
longitude: -1.985401 and latitude 52.397618. The coordinates will
obviously be different depending on your location.
It is again worth noting that you can download the complete project files,
images, etc. from the book’s companion website: www.androidjava.website.
REFERENCES
1. https://www.tutorialspoint.com/android/
2. https://www.raywenderlich.com/category/android
3. https://www.youtube.com/playlist?list=PLB03EA9545DD188C3
4. https://developer.android.com/index.html
5. https://www.udacity.com/course/android-development-for-beginners-
ud837
6. http://www.instructables.com/id/How-To-Create-An-Android-
AppWith-Android-Studio/
7. http://www.androidauthority.com/android-studio-tutorial-
beginners637572/
8. https://www.codecademy.com/learn/learn-java
9. https://www.tutorialspoint.com/java/
207 | P a g e