package com.allyourcode.a10_11;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
The code declares a class named MainActivity
. This name MainActivity
isn't part of the Android API library. It's a name that you make up when you create a new Android project. (Actually, Android Studio makes up the name. You accept the name or change it to some other name when you follow the steps to create a new project.)
The MainActivity
class extends a class that belongs to Android's SDK library, namely, the AppCompatActivity
class. In other words, the MainActivity
object is an AppCompatActivity
object. The MainActivity
object has all the rights and responsibilities that any AppCompatActivity
instance has. For example, the MainActivity
has an onCreate
method, which it override.
In fact, the MainActivity
class inherits about 460 lines of code from Android's AppCompatActivity
class, which inherits about 1,000 lines from Android's FragmentActivity
class, which inherits about 6,700 lines from Android's Activity class. The inherited methods include ones such as getCallingActivity
, getCallingPackage
, getParent
, getTitle
, getTitleColor
, getWindow
, onBackPressed
, onKeyDown
, onKeyLongPress
, onLowMemory
, onMenuItemSelected
, setTitle
, setTitleColor
, startActivity
, finish, and many, many others. You inherit all this functionality with two simple words: extends AppCompatActivity
.
In the terminology of familial relationships, your MainActivity
class is a descendant of Android's Activity
class. Your MainActivity
class is a kind of Activity
.
AppCompatActivity
class.
Bookmark the page for easy access to Android's API library documentation.
In addition to being a subclass, theAppCompatActivity
class implements a bunch of interfaces, including the AppCompatCallback
interface, the TaskStackBuilder
interface, and others. You don't have to remember any of this. If you ever need to know it, you can look it up on Android's documentation page.
Java's super keyword, revisited
The wordsuper
stands for the superclass's constructor. Different code used the super
keyword in a different ways. Yes, super
always has something to do with a class's parent class. But, no, super
doesn't always refer to the parent class's constructor.In an onCreate
method, the call super.onCreate(savedInstanceState)
sends savedInstanceState
to the parent class's onCreate
method. The parent class is the AppCompatActivity
class. So Java calls the AppCompatActivit
y class's onCreate
method.
The AppCompatActivity
class's onCreat
e method contains its own call to super.onCreate(savedInstanceState)
. The AppCompatActivity
class's parent is the FragmentActivity
class. So Java passes savedInstanceState
to the FragmentActivity
class's onCreate
method. And so on.
It's not until you get to the Activity
class — your MainActivity
class's great-grandparent — that the code makes direct use of the savedInstanceState
variable. From this savedInstanceState
information, the code puts the activity back the way it was before the system destroyed it.
Casting, again
When you callfindViewById
, Java doesn't know what kind of view it will find. The findViewById
method always returns a View
instance, but lots of Android's classes extend the View
class. For example, the classes Button
, TextView
, ImageView
, CheckBox
, Chronometer
, and RatingBar
all extend Android's View
class. If you type the following code:<strong>// DON'T DO THIS!!</strong>
TextView textView;
textView = findViewById(R.id.textView);
Java lets out a resounding, resentful roar: “How dare you assume that the object returned by a call to findViewById
refers to an instance of the TextView
class!” (Actually, Java quietly and mechanically displays an Incompatible types error message in Android Studio's editor.)
Narrowing means trying to assign a long
value to an int
value. A long
value has 64 bits, and an int
value has only 32 bits. So the attempt at narrowing fails. In the code you find here, the bad findViewById
call is another attempt to do narrowing — assigning the View
value returned by a method call to a TextView
variable. The TextView
class is a subclass of the View
class, so the assignment fails miserably.
appease the Java gods by adding a casting operator to the code. You tell Java to convert whatever pops out of the findViewById
method call into a TextView
object.
textView = <strong>(TextView)</strong> findViewById(R.id.textView1);
While you're typing the code, Java humors you and says, “Your casting operator shows me that you're aware of the difference between a TextView
and any old View
. I’ll do my best to interpret the View
object that I find at runtime as a TextView
object.” (Actually, while you're typing the code, Java says nothing. The fact that Java doesn't display any error messages when you use this casting trick is a good sign. Java's casting feature saves the day!)
Casting prevents you from seeing an error message while you develop your code. In that way, casting is quite a useful feature of Java. But casting can't save you if your code contains runtime errors. When you type
textView = (TextView) findViewById(R.id.textView1);
you verify that the name textView
represents a TextView
widget. When the app runs, Java grabs the R.id.textView
widget from the activity_main.xml
file, and everything works just fine. But you may sometimes forget to check your R.java
names against the components in the XML file. A call to findViewById
surprisingly spits out a Button
component when your casting tells Java to expect a TextView
widget. When this happens, Java chokes on the casting operator and your app crashes during its run. Back to the drawing board!