Updated: January 2020.
In Part 1 of this beginner's introduction to Android Studio, you set up Android Studio in your development environment and got to know the user interface. Now, in Part 2, you'll code your first app.
The animated mobile app consists of a single activity, which presents Google's Android robot character and a button for animating the character. Clicking the button causes the character to gradually change color from green to red to blue, then back to green. While the app isn't especially useful, writing it will help you get comfortable with using Android Studio. In Part 3, you'll build and run the app using an Android device emulator and a Kindle Fire tablet.
Note that this series has been updated for Android Studio 3.2.1, the current stable release as of this writing.
Android Studio's Project and editor windows
I introduced Android Studio's main window at the end of Part 1. This window is divided into several areas, including a Project window where you identify an app's resource files, and various editor windows where you'll write the code and specify resources for mobile apps in Android Studio. The Project window and an editor window are shown in Figure 1.
Figure 1. Android Studio's Project window and an editor window (click to enlarge)
The Project window highlights W2A, which is the name of the app's W2A.java
source file (although the .java
file extension isn't shown). Corresponding to W2A is an editor window, reached by double-clicking W2A in the Project window. The editor window reveals the file's current contents, in this case the skeletal Java source code for the app's main activity.
Each editor window is associated with a tab. For example, W2A's editor window is associated with a W2A.java tab. A second tab identified as main.xml (the default XML-based layout for the app's main activity) is also shown. You move from one editor window to another by clicking the window's tab.
The Android example app
The example app (W2A.java) consists of a main activity that displays the Android robot character and a button. When the user presses the button, the robot animates through a series of colors. In this section, we'll explore the activity's source code and resources.
Explore and code the Android example app
The activity's source code is stored in the file W2A.java
, presented in Listing 1.
Listing 1. W2A.java
package ca.javajeff.w2a;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
public class W2A extends Activity
{
AnimationDrawable androidAnimation;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ImageView androidImage = (ImageView) findViewById(R.id.android);
androidImage.setBackgroundResource(R.drawable.android_animate);
androidAnimation = (AnimationDrawable) androidImage.getBackground();
final Button btnAnimate = (Button) findViewById(R.id.animate);
View.OnClickListener ocl;
ocl = new View.OnClickListener()
{
@Override
public void onClick(View v)
{
androidAnimation.stop();
androidAnimation.start();
}
};
btnAnimate.setOnClickListener(ocl);
}
}
The W2A.java
file starts with a package statement, which names the package (ca.javajeff.w2a
) that stores the W2A
class. This is followed by a series of import statements for various Android API types. Next, the code describes the W2A
class, which extends android.app.Activity
.
W2A
first declares an androidAnimation
instance field of type android.graphics.drawable.AnimationDrawable
. Objects of type AnimationDrawable
describe frame-by-frame animations, in which the current drawable is replaced with the next drawable in the animation sequence.
The onCreate() method
All of the app's work takes place in W2A
's overriding onCreate(Bundle)
method: no other methods are required, which helps to keep this app simple.
onCreate(Bundle)
first invokes its same-named superclass method, a rule that must be followed by all overriding activity methods.
This method then executes setContentView(R.layout.main)
to establish the app's user interface. R.layout.main
is an identifier (ID) for an application resource, which resides in a separate file. You interpret this ID as follows:
R
is the name of a class that's generated when the app is being built. This class is namedR
because its content identifies various kinds of application resources, including layouts, images, strings, and colors.layout
is the name of a class that's nested withinR
. An application resource whose ID is stored in this class describes a specific layout resource. Each kind of application resource is associated with a nested class that's named in a similar fashion. For example,string
identifies string resources.main
is the name of anint
-based constant declared withinlayout
. This resource ID identifies the main layout resource. Specifically,main
refers to amain.xml
file that stores the main activity's layout information.main
isW2A
's only layout resource.
Passing R.layout.main
to Activity
's void setContentView(int layoutResID)
method instructs Android to create a user interface screen using the layout information stored in main.xml
. Behind the scenes, Android creates the user interface components described in main.xml
and positions them on the device screen as specified by main.xml
's layout data.
The screen is based on views (abstractions of user interface components) and view groups (views that group related user interface components). Views are instances of classes that subclass the android.view.View
class and are analogous to AWT/Swing components. View groups are instances of classes that subclass the abstract android.view.ViewGroup
class and are analogous to AWT/Swing containers. Android refers to specific views (such as buttons or spinners) as widgets.
Continuing, onCreate(Bundle)
executes ImageView androidImage = (ImageView) findViewById(R.id.android);
. This statement first calls View
's View findViewById(int id)
method to find the android.widget.ImageView
element declared in main.xml
and identified as android
. It instantiates ImageView
and initializes it to the values declared in the main.xml
file. The statement then saves this object's reference in local variable androidImage
.
ImageView and AnimationDrawable
Next, the androidImage.setBackgroundResource(R.drawable.android_animate);
statement invokes ImageView
's inherited (from View
) void setBackgroundResource(int resID)
method, setting the view's background to the resource identified by resID
. The R.drawable.android_animate
argument identifies an XML file named android_animate.xml
(presented later), which stores information on the animation, and which is stored in res
's drawable
subdirectory. The setBackgroundResource()
call links the androidImage
view to the sequence of images described by android_animate.xml
, which will be drawn on this view. The initial image is drawn as a result of this method call.
ImageView
lets an app animate a sequence of drawables by calling AnimationDrawable
methods. Before the app can do this, it must obtain ImageView
's AnimationDrawable
. The androidAnimation = (AnimationDrawable) androidImage.getBackground();
assignment statement that follows accomplishes this task by invoking ImageView
's inherited (from View
) Drawable getBackground()
method. This method returns the AnimationDrawable
for the given ImageView
, which is subsequently assigned to the androidAnimation
field. The AnimationDrawable
instance is used to start and stop an animation, a process I'll describe shortly.
Finally, onCreate(Bundle)
creates the Animate button. It invokes findByViewId(int)
to obtain the button information from main.xml
, then instantiates the android.widget.Button
class.
It then employs the View
class's nested onClickListener
interface to create a listener object. This object's void onClick(View v)
method is invoked whenever the user clicks the button. The listener is registered with its Button
object by calling View
's void setOnClickListener(AdapterView.OnClickListener listener)
method.
To stop, then start the animation, Animate's click listener invokes androidAnimation.stop();
followed by androidAnimation.start();
. The stop()
method is called before start()
to ensure that a subsequent click of the Animate button causes a new animation to begin.
Update and save your code
Before we continue, replace the skeletal code in your W2A.java tab with the code from Listing 1. Save the contents of this window by pressing Ctrl+S, or select Save All from the File menu.
Coding the Android app's main.xml
The app's main activity is associated with an XML-based layout, which is stored in file main.xml
, and which is presented in Listing 2.
Listing 2. main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:background="#ffffff">
<ImageView android:id="@+id/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dip"/>
<Button android:id="@+id/animate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/animate"/>
</LinearLayout>
After the XML declaration, Listing 2 declares a LinearLayout
element that specifies a layout (a view group that arranges contained views on an Android device's screen in some manner) for arranging contained widgets (including nested layouts) either horizontally or vertically across the screen.
The <LinearLayout>
tag specifies several attributes for controlling this linear layout. These attributes include the following:
orientation
identifies the linear layout as horizontal or vertical. Contained widgets are laid out horizontally or vertically, and the default orientation is horizontal."horizontal"
and"vertical"
are the only legal values that can be assigned to this attribute.layout_width
identifies the width of the layout. Legal values include"fill_parent"
(to be as wide as the parent) and"wrap_content"
(to be wide enough to enclose content). (Note thatfill_parent
was renamed tomatch_parent
in Android 2.2, but is still supported and widely used.)layout_height
identifies the height of the layout. Legal values include"fill_parent"
(to be as tall as the parent) and"wrap_content"
(to be tall enough to enclose content).gravity
identifies how the layout is positioned relative to the screen. For example,"center"
specifies that the layout should be centered horizontally and vertically on the screen.background
identifies a background image, a gradient, or a solid color. For simplicity, I've hardcoded a hexadecimal color identifier to signify a solid white background (#ffffff
). (Colors would normally be stored incolors.xml
and referenced from this file.)
The LinearLayout
element encapsulates ImageView
and Button
elements. Each of these elements specifies an id
attribute, which identifies the element so that it can be referenced from code. The resource identifier (special syntax that begins with @
) assigned to this attribute begins with the @+id
prefix. For example, @+id/android
identifies the ImageView
element as android
; this element is referenced from code by specifying R.id.android
.
These elements also specify layout_width
and layout_height
attributes for determining how their content is laid out. Each attribute is assigned wrap_content
so that the element will appear at its natural size.
ImageView
specifies a layout_marginBottom
attribute to identify a space separator between itself and the button that follows vertically. The space is specified as 10 dips, or density-independent pixels. These are virtual pixels that apps can use to express layout dimensions/positions in a screen density-independent way.