A Line by Line Look at the Code
Figure 1. The Confuse Text app in action!
In this lesson, we will look at the basic Activity stub class line by line. There is not much code here, but explaining the meaning of the code is not trivial! The main entry point of our application is named ConfuseText.java. Here again is the default code for our application.
package com.google.sites.site.jalcomputing.android.app;
import android.app.Activity;
import android.os.Bundle;
public class ConfuseText extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Figure 2. The ConfuseText.java class
Warning: This is NOT a java tutorial, nor is it an OOP (object oriented programming) tutorial.
If you are interested in learning about OOP and know C#, you can read my twisted tutorial on object oriented programming in c#.
General Overview
This simple class creates an "Activity" or User Interface when the user launches the app. Activities are separate from "Intents", which are request for starting an action. You do not actually directly construct an activity by a call to new MyActivity(). Instead, you create an intent as in:
Intent i= new Intent(this, MyActivity.class);
startActivity(i);
and call startActivity(intent). So Activities generally do not have constructors that take parameters.
More complicated user interfaces can be generated using XML in a file called main.xml. String values can be extracted from the user interface into a separate file for International localization into yet another XML file called strings.xml. Both of these XML files are considered "Resources" and are stored in a separate folder hierarchy "res"/"layout". Information about the app such as versioning, is contained in a manifest.xml file.
We are now going to look more closely at the ten lines of code in our app! I recommend a quick bathroom break and a large mug of coffee :)
package
Let's look at the first line that simply declares the namespace for our application.
package com.google.sites.site.jalcomputing.android.app;
The first word package is a keyword or a word reserved for use by the compiler. This word must be the first compilable word in the java source file. The local name of the class file, ConfuseText, will be appended to the package name to create the fully qualified or non-ambiguous class name for the class. In our case, the fully qualified class name will be com.google.sites.site.jalcomputing.android.app.ConfuseText. It IS possible for another developer to name a class with the same local name ConfuseText, but that class will have a different fully qualified name such as com.anotherdeveloper.ConfuseText. This will avoid a name collision.
import
The next two lines of code simplify the coding process by telling the compiler where to look for code identified in the class file by local name only. The java compiler will normally look first in java.lang for the class definitions.
import android.app.Activity;
import android.os.Bundle;
These two import statements gives the compiler two additional places to look for class files identified by local name only. If you comment out the first import statement, the class will not compile!
//import android.app.Activity; //--> leads to compiler errors!
import android.os.Bundle;
Instead you will get errors, visible in the "Problems" pane such as "Activity cannot be resolved to a type." The line of code that generates this error Is:
public class ConfuseText extends Activity {
You could eliminate this error by using the fully qualified name for the Activity class as in:
public class ConfuseText extends android.app.Activity {
class
A class is a software construct, a blueprint that can describe both values and behavior. It contains the information needed to create working code in memory. When you create an object, you use the information in the class to generate working code. An object is an instance of a class. A specific class describes how to create a specific object in memory. So the class must contain information about the values and behaviors that each object will implement. So we are defining a blueprint to create objects of class ConfuseText.
public class ConfuseText extends Activity {
...
}
Somewhere in the project code an instance of our class will be created using the keyword new as in:
ConfuseText ct= new ConfuseText();
This code creates an instance of the ConfuseText class, an object with values and behavior stored in memory. The compiler may optimize the generated code so that redundant method code may be shared by more than one instance of the class.
extends
The extends keyword tells the compiler to reuse the code in the Activity class, if possible, and allows us to add new behavior and values to the Activity class. This magic is done through inheritance. Inheritance allows programmers to modify or extend (or inherit) the properties and behavior (methods) of a class. It promotes "code reuse", the holy grail of programming.
public class ConfuseText extends Activity {
...
}
Let's look at the methods declared in the Activity class:
public class Activity extends ApplicationContext {
protected void onCreate(Bundle savedInstanceState);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onPause();
protected void onStop();
protected void onDestroy();
}
Our class ConfusedText inherits these methods since they are declared protected, not private.
Annotations, @Override
@Override
This is an annotation (@), a mechanism for adding meta data to Java source code. Annotations in class files can be "retained by the Java VM" and retrieved at run time using reflection. Annotations can also be used to tell the compiler to do things such as suppress warnings (@Suppresswarnings), generate warnings (@deprecated) or to generate warnings if a condition is not met (@override). There are three simple annotations reserved by the compiler (Override, Deprecated and Suppresswarnings) for "syntactic purposes." The @Override annotation tells the compiler to generate a warning if the method does not override the method of the same name in the super-class. In this case the super-class or parent-class is the class Activity and the method that should be overridden is the Activity method onCreate(..). In contrast, C# has a keyword override.
Overriding vs Shadowing
In general when you extend a class, you shadow fields with the same name in the base class and override virtual methods with the same name and parameter list in the base class. Overriding makes the base class method invisible. Shadowing a field, only hides the field from view. You can still explicitly touch the hidden shadowed field if you wish. You cannot touch an invisible overridden method.
So in our class, we override the virtual method Activity.onCreate making the onCreate code in the base class Activity invisible to users of our class. We replace the base class method Activity.onCreate(...) with our new version.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
Overriding
The ConfuseText method onCreate overrides the base class method of the same name, making the base class method of the same name invisible. Even when objects of class ConfuseText are touched with references of type Activity, the code that will be called is ConfuseText.onCreate(...), not Activity.onCreate(...). This make sense since we just said that overriding makes the base class method of the same name invisible, or unreachable or untouchable (hey you know what I mean here). For instance:
Activity a= new ConfuseText(); // a is a reference variable of type Activity*
a.onCreate(...); //--> calls ConfuseText.onCreate(...) not Activity.onCreate(...)
This preserves the magic of polymorphism.
*Remember our mantra. "Objects have class, references (reference variables) have type."
super
By convention, the ConfuseText class is also called the subclass of Activity and the class Activity is also called the super-class of ConfuseText. The following line of code just calls the now invisible code in the superclass Activity.onCreate(...).
super.onCreate(savedInstanceState);
We can do this inside the overriding class. In fact, it has been argued that it is good practice to call the overridden base class method before adding new behaviors.
onCreate(Bundle)
According to the Android docs, "An activity is a single, focused thing that the user can do" and onCreate(Bundle) "is where you initialize your activity."
super.onCreate(savedInstanceState);
In this call, we simply pass the method in-parameter savedInstanceState to the super-class method of the same name.
Note: When the user changes the orientation of the Android device, the current activity is KILLED and information about the View, and only about the View, is saved and passed back in the bundle savedInstanceState. The OS automagically uses that info to restore the View state in onCreate. If your class has state that is not stored in a View state, you are responsible for saving the state (see onSaveInstanceState) and restoring the state using the info in savedInstanceState! You can learn about saving instance state here.
setContentView(View)
According to the Android docs, this method is used to "set the activity content from a layout resource." In our case, the resource used to set the content is found in R.layout.main.
setContentView(R.layout.main);
The file main.xml is found by navigating the package contents using the Package Explorer pane as in res-->layout-->main.xml which corresponds to R.layout.main.
main.xml
Here again is the contents of the main.xml file that describes the actual layout to be used.
<?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"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>
At this stage, the layout simply consist of a TextView in a linear layout with a text string defined at @string/hello.
strings.xml
Here again is the contents of the string resource file strings.xml.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, Confuse Text!</string>
<string name="app_name">Confuse Text</string>
</resources>
At this stage, the string @string/hello has the value "Hello World, Confuse Text!"
Wow. That definitely was not a trivial explanation for ten lines of code. My condolences.
JAL